A lightweight, cross-platform email sending library for .NET Standard 2.0+, .NET Core, and .NET 5+.
- ✅ .NET Standard 2.0 compatible (works with .NET Framework 4.6.1+, .NET Core 2.0+, .NET 5+)
- ✅ Multiple recipients (To, Cc, Bcc)
- ✅ HTML and plain text emails
- ✅ Attachments support with size validation
- ✅ SMTP provider with MailKit
- ✅ Fluent API
- ✅ Optional logging support (Microsoft.Extensions.Logging)
- ✅ Automatic retry with exponential backoff
- ✅ Email validation (format, required fields)
- ✅ Async/await throughout
- ✅ Structured result objects (no exceptions for send failures)
dotnet add package FluentMailservices.AddFluentMail(options =>
{
options.Host = "smtp.gmail.com";
options.Port = 587;
options.Username = "your-email@gmail.com";
options.Password = "your-password";
options.UseSsl = true;
});public class MyService
{
private readonly IEmailService _emailService;
public MyService(IEmailService emailService)
{
_emailService = emailService;
}
public async Task SendWelcomeEmail()
{
var message = new EmailMessage()
.From("noreply@example.com", "My App")
.To("user@example.com", "John Doe")
.WithSubject("Welcome!")
.WithHtmlBody("<h1>Welcome to our service!</h1>");
var result = await _emailService.SendAsync(message);
if (result.IsSuccess)
{
Console.WriteLine($"Email sent! MessageId: {result.MessageId}");
}
else
{
Console.WriteLine($"Failed: {result.ErrorMessage}");
}
}
}var message = new EmailMessage()
.From("sender@example.com")
.To("user1@example.com")
.To("user2@example.com")
.To(new[] { "user3@example.com", "user4@example.com" })
.Cc("manager@example.com")
.Bcc("admin@example.com")
.WithSubject("Team Update")
.WithBody("Hello team!");
var result = await emailService.SendAsync(message);var message = new EmailMessage()
.From("sender@example.com")
.To("recipient@example.com")
.WithSubject("Invoice")
.WithBody("Please find attached invoice")
.WithAttachment(new EmailAttachment("invoice.pdf", fileStream, "application/pdf"));
var result = await emailService.SendAsync(message);var options = new SmtpOptions
{
Host = "smtp.gmail.com",
Port = 587,
Username = "your-email@gmail.com",
Password = "your-password",
UseSsl = true
};
var provider = new SmtpEmailProvider(options);
var emailService = new EmailService(provider);
var message = new EmailMessage()
.From("sender@example.com")
.To("recipient@example.com")
.WithSubject("Test")
.WithBody("Hello!");
var result = await emailService.SendAsync(message);public class SmtpOptions
{
public string Host { get; set; } // SMTP server host
public int Port { get; set; } // SMTP server port (default: 587)
public string Username { get; set; } // SMTP username
public string Password { get; set; } // SMTP password
public bool UseSsl { get; set; } // Use SSL/TLS (default: true)
public string? DefaultFromEmail { get; set; } // Optional default sender
public string? DefaultFromName { get; set; } // Optional default sender name
public long MaxAttachmentSize { get; set; } // Max attachment size in bytes (default: 20MB)
public int MaxRetries { get; set; } // Retry attempts for failures (default: 3)
public int RetryDelayMs { get; set; } // Initial retry delay in ms (default: 1000)
}services.AddFluentMail(options =>
{
options.Host = "smtp.gmail.com";
options.Port = 587;
options.Username = "your-email@gmail.com";
options.Password = "your-password";
options.UseSsl = true;
// Attachment validation
options.MaxAttachmentSize = 10 * 1024 * 1024; // 10MB limit
// Retry configuration
options.MaxRetries = 5; // Retry up to 5 times
options.RetryDelayMs = 2000; // Start with 2 second delay
// Exponential backoff: 2s, 4s, 8s, 16s, 32s
});The library integrates seamlessly with Microsoft.Extensions.Logging:
// In Startup.cs or Program.cs
services.AddLogging(builder =>
{
builder.AddConsole();
builder.AddDebug();
});
services.AddFluentMail(options => { ... });Log output includes:
- Recipient count
- Send success/failure
- Message IDs
- Validation errors
If logging is not configured, the library works silently without errors.
The library automatically validates:
- Email address format (RFC-compliant regex)
- Required fields (From, To, Subject)
- Total attachment size
- All recipient email addresses
var result = await emailService.SendAsync(message);
if (!result.IsSuccess)
{
// Possible validation errors:
// - "Valid sender email is required"
// - "At least one recipient is required"
// - "Invalid email address: xyz"
// - "Total attachment size (25MB) exceeds limit (20MB)"
Console.WriteLine(result.ErrorMessage);
}Automatic retry with exponential backoff for transient failures:
MaxRetries = 3, RetryDelayMs = 1000
// Attempt 1: Immediate
// Attempt 2: Wait 1s (1000ms * 2^0)
// Attempt 3: Wait 2s (1000ms * 2^1)
// Attempt 4: Wait 4s (1000ms * 2^2)Retries are automatic and transparent. Check logs to see retry attempts.
cd tests/EmailSender.Tests
dotnet testThe test suite includes:
- Email validation tests
- Fluent API tests
- Retry logic tests
- Error handling tests
- SMTP provider tests
cd src/EmailSender
dotnet pack -c ReleaseMIT