Nager.SmtpServerCore is a lightweight yet powerful SMTP server implementation in C#.
Built entirely in .NET, it leverages the Task Parallel Library (TPL) for maximum performance.
Nager.SmtpServerCore is based on the original SmtpServer library by cosullivan. This repository represents an independent continuation and further development of the project, focusing on modern .NET standards and long-term maintainability.
Check the Changelog
SmtpServer currently supports the following extensions:
- STARTTLS
- SIZE
- PIPELINING
- 8BITMIME
- SMTPUTF8
- AUTH PLAIN LOGIN
The package is available on NuGet
PM> install-package Nager.SmtpServerCoreStarting a basic SMTP server requires only a few lines of code:
var options = new SmtpServerOptionsBuilder()
.ServerName("localhost")
.Port(25, 587)
.Build();
var smtpServer = new SmtpServer.SmtpServer(options, ServiceProvider.Default);
await smtpServer.StartAsync(CancellationToken.None);There are three hooks that can be implemented; IMessageStore, IMailboxFilter, and IUserAuthenticator.
var options = new SmtpServerOptionsBuilder()
.ServerName("localhost")
.Endpoint(builder =>
builder
.Port(9025, true)
.AllowUnsecureAuthentication(false)
.Certificate(CreateCertificate()))
.Build();
var serviceProvider = new ServiceProvider();
serviceProvider.Add(new SampleMessageStore());
serviceProvider.Add(new SampleMailboxFilter());
serviceProvider.Add(new SampleUserAuthenticator());
var smtpServer = new SmtpServer.SmtpServer(options, serviceProvider);
await smtpServer.StartAsync(CancellationToken.None);
// to create an X509Certificate for testing you need to run MAKECERT.EXE and then PVK2PFX.EXE
// http://www.digitallycreated.net/Blog/38/using-makecert-to-create-certificates-for-development
static X509Certificate2 CreateCertificate()
{
var certificate = File.ReadAllBytes(@"Certificate.pfx");
return new X509Certificate2(certificate, "P@ssw0rd");
}public class SampleMessageStore : MessageStore
{
public override async Task<SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, ReadOnlySequence<byte> buffer, CancellationToken cancellationToken)
{
await using var stream = new MemoryStream();
var position = buffer.GetPosition(0);
while (buffer.TryGet(ref position, out var memory))
{
await stream.WriteAsync(memory, cancellationToken);
}
stream.Position = 0;
var message = await MimeKit.MimeMessage.LoadAsync(stream, cancellationToken);
Console.WriteLine(message.TextBody);
return SmtpResponse.Ok;
}
}public class SampleMailboxFilter : IMailboxFilter, IMailboxFilterFactory
{
public Task<MailboxFilterResult> CanAcceptFromAsync(ISessionContext context, IMailbox @from, int size, CancellationToken cancellationToken)
{
if (String.Equals(@from.Host, "test.com"))
{
return Task.FromResult(MailboxFilterResult.Yes);
}
return Task.FromResult(MailboxFilterResult.NoPermanently);
}
public Task<MailboxFilterResult> CanDeliverToAsync(ISessionContext context, IMailbox to, IMailbox @from, CancellationToken token)
{
return Task.FromResult(MailboxFilterResult.Yes);
}
public IMailboxFilter CreateInstance(ISessionContext context)
{
return new SampleMailboxFilter();
}
}public class SampleUserAuthenticator : IUserAuthenticator, IUserAuthenticatorFactory
{
public Task<bool> AuthenticateAsync(ISessionContext context, string user, string password, CancellationToken token)
{
Console.WriteLine("User={0} Password={1}", user, password);
return Task.FromResult(user.Length > 4);
}
public IUserAuthenticator CreateInstance(ISessionContext context)
{
return new SampleUserAuthenticator();
}
}