GridLab Email Sending Service - Skills Guide¶
Skill Type: Communication & Messaging
Technology Stack: .NET, ABP Framework, SMTP
Complexity Level: Beginner
Last Updated: 2024
📋 Overview¶
The GridLab Email Service provides enterprise-grade email sending capabilities with SMTP integration, background job support, and comprehensive configuration options for ABP Framework applications.
Key Capabilities¶
- ✅ Simple and intuitive
IEmailSenderservice - ✅ Flexible SMTP configuration
- ✅ Background job integration for async sending
- ✅ Template-based email support
- ✅ SSL/TLS encryption support
- ✅ Multiple authentication methods
Prerequisites¶
- .NET 9.0 or higher
- SMTP server access (Gmail, SendGrid, etc.)
- NuGet package manager
🚀 Quick Start¶
Step 1: Install NuGet Package¶
Install the GridLab.Abp.Emailing package from NuGet:
Install-Package GridLab.Abp.Emailing
Package Information:
- Package Name: GridLab.Abp.Emailing
- Repository: GitLab - GridLab ABP Framework
- NuGet: GridLab.Abp.Emailing
Step 2: Add Module Dependency¶
Add the AbpGridLabEmailingModule to your ABP module's dependency list:
[DependsOn(
//...other dependencies
typeof(AbpGridLabEmailingModule)
)]
public class YourModule : AbpModule
{
}
Step 3: Configure Email Settings¶
Locate appsettings.json in your project and add email configuration:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"Email": {
"FromAddress": "noreply@gridlab.io",
"FromDisplayName": "GridLab GMS²",
"UserName": "noreply",
"Password": "your-smtp-password",
"Host": "smtp.gmail.com",
"Port": 587,
"EnableSsl": true
},
"AllowedHosts": "*"
}
⚙️ Configuration Reference¶
Email Options¶
Configure email options in your module's ConfigureServices method:
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<EmailOptions>(options =>
{
options.FromAddress = configuration["Email:FromAddress"];
options.FromDisplayName = configuration["Email:FromDisplayName"];
options.UserName = configuration["Email:UserName"];
options.Password = configuration["Email:Password"];
options.Host = configuration["Email:Host"];
options.Port = int.Parse(configuration["Email:Port"] ?? "587");
options.EnableSsl = bool.Parse(configuration["Email:EnableSsl"] ?? "true");
options.UseDefaultCredentials = false;
});
}
Configuration Properties¶
| Property | Description | Default Value | Required |
|---|---|---|---|
| Host | SMTP server hostname or IP address | smtp.gmail.com | ✅ Yes |
| Port | SMTP server port number | 587 | ✅ Yes |
| UserName | SMTP authentication username | Empty | ✅ Yes |
| Password | SMTP authentication password | Empty | ✅ Yes |
| Domain | Domain for SMTP authentication | Empty | ❌ No |
| EnableSsl | Enable SSL/TLS encryption | true | 🟡 Recommended |
| UseDefaultCredentials | Use Windows credentials | false | ❌ No |
| FromAddress | Default sender email address | Empty | ✅ Yes |
| FromDisplayName | Default sender display name | GridLab GMS² | ❌ No |
💡 Usage Examples¶
Basic Email Sending¶
public class NotificationService : ITransientDependency
{
private readonly IEmailSender _emailSender;
private readonly ILogger<NotificationService> _logger;
public NotificationService(
IEmailSender emailSender,
ILogger<NotificationService> logger)
{
_emailSender = emailSender;
_logger = logger;
}
public async Task SendWelcomeEmailAsync(string userEmail, string userName)
{
try
{
await _emailSender.SendAsync(
to: userEmail,
subject: "Welcome to GridLab!",
body: $"Hello {userName},<br><br>Welcome to our platform!<br><br>Best regards,<br>GridLab Team",
isBodyHtml: true
);
_logger.LogInformation("Welcome email sent to {Email}", userEmail);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to send welcome email to {Email}", userEmail);
throw;
}
}
}
HTML Email with Template¶
public class TemplateEmailService : ITransientDependency
{
private readonly IEmailSender _emailSender;
private readonly ITemplateRenderer _templateRenderer;
public TemplateEmailService(
IEmailSender emailSender,
ITemplateRenderer templateRenderer)
{
_emailSender = emailSender;
_templateRenderer = templateRenderer;
}
public async Task SendPasswordResetEmailAsync(string email, string resetToken)
{
var model = new
{
ResetLink = $"https://yourapp.com/reset-password?token={resetToken}",
ExpiryHours = 24
};
var body = await _templateRenderer.RenderAsync(
"EmailTemplates/PasswordReset",
model
);
await _emailSender.SendAsync(
to: email,
subject: "Password Reset Request",
body: body,
isBodyHtml: true
);
}
}
Batch Email Sending¶
public class BulkEmailService : ITransientDependency
{
private readonly IEmailSender _emailSender;
private readonly IBackgroundJobManager _backgroundJobManager;
public BulkEmailService(
IEmailSender emailSender,
IBackgroundJobManager backgroundJobManager)
{
_emailSender = emailSender;
_backgroundJobManager = backgroundJobManager;
}
public async Task SendNewsletterAsync(List<string> recipients, string content)
{
foreach (var recipient in recipients)
{
// Queue emails as background jobs for better performance
await _backgroundJobManager.EnqueueAsync(
new SendEmailArgs
{
To = recipient,
Subject = "Monthly Newsletter",
Body = content,
IsBodyHtml = true
}
);
}
}
}
Email with Attachments¶
public class DocumentEmailService : ITransientDependency
{
private readonly IEmailSender _emailSender;
public DocumentEmailService(IEmailSender emailSender)
{
_emailSender = emailSender;
}
public async Task SendInvoiceEmailAsync(string email, byte[] pdfData, string invoiceNumber)
{
var message = new MailMessage
{
To = { email },
Subject = $"Invoice #{invoiceNumber}",
Body = $"Please find attached invoice #{invoiceNumber}.",
IsBodyHtml = true
};
var attachment = new Attachment(
new MemoryStream(pdfData),
$"Invoice_{invoiceNumber}.pdf",
"application/pdf"
);
message.Attachments.Add(attachment);
await _emailSender.SendAsync(message);
}
}
🔧 Advanced Scenarios¶
Background Job Integration¶
[DependsOn(typeof(AbpBackgroundJobsModule))]
public class YourModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpBackgroundJobOptions>(options =>
{
options.IsJobExecutionEnabled = true;
});
}
}
public class SendEmailJob : AsyncBackgroundJob<SendEmailArgs>, ITransientDependency
{
private readonly IEmailSender _emailSender;
public SendEmailJob(IEmailSender emailSender)
{
_emailSender = emailSender;
}
public override async Task ExecuteAsync(SendEmailArgs args)
{
await _emailSender.SendAsync(
args.To,
args.Subject,
args.Body,
args.IsBodyHtml
);
}
}
SMTP Provider Examples¶
Gmail Configuration¶
{
"Email": {
"Host": "smtp.gmail.com",
"Port": 587,
"EnableSsl": true,
"UserName": "your-email@gmail.com",
"Password": "your-app-specific-password"
}
}
SendGrid Configuration¶
{
"Email": {
"Host": "smtp.sendgrid.net",
"Port": 587,
"EnableSsl": true,
"UserName": "apikey",
"Password": "your-sendgrid-api-key"
}
}
Office 365 Configuration¶
{
"Email": {
"Host": "smtp.office365.com",
"Port": 587,
"EnableSsl": true,
"UserName": "your-email@yourdomain.com",
"Password": "your-password"
}
}
📚 Best Practices¶
✅ Do's¶
- Use environment variables for sensitive SMTP credentials
- Enable SSL/TLS for secure transmission
- Implement retry logic for failed email sends
- Use background jobs for non-critical emails
- Validate email addresses before sending
- Log email sending activities
❌ Don'ts¶
- Don't hardcode SMTP passwords in source code
- Don't send emails synchronously in request handlers
- Don't expose email addresses in logs
- Don't send emails without user consent
- Don't use production SMTP in development
🔍 Troubleshooting¶
Common Issues¶
Issue: SMTP authentication failed
- Solution: Verify username and password are correct
- Solution: For Gmail, use App-Specific Password instead of account password
- Solution: Check if "Less secure app access" is enabled (if applicable)
Issue: Connection timeout
- Solution: Verify SMTP host and port are correct
- Solution: Check firewall settings
- Solution: Ensure network connectivity to SMTP server
Issue: SSL/TLS errors
- Solution: Verify
EnableSslis set totruefor port 587 - Solution: Check certificate validation settings