The example shows how to write a multi-threaded SMTP server in C#, which runs in a Windows service, listens to incoming connections, accepts incoming mail, and relays mail to external recipients.
The source code for the example is available on
GitHub
Creating a service project in Visual Studio and setting up the components:
After creating a Windows Service project (.NET Framework), you need to put the following components on to the Service form: SmtpServer, SmtpFileHandler, SmtpRelay, and Timer. You need to add user accounts to the SmtpServer.UserAccounts collection, specify both the mailbox and the relay folders for the SmtpFileHandler component, add a reference to the SmtpServer instance to the SmtpFileHandler.Server component, and set up the timeout interval for the Timer component.
You can start the SMTP server automatically when the Windows service runs:
protected override void OnStart(string[] args)
{
smtpServer1.Start();
timer1.Enabled = true;
}
protected override void OnStop()
{
smtpServer1.Stop();
}
Delivering outgoing mail to end-recipients:
The server automatically saves all incoming mail for external recipients to the SmtpFileHandler.RelayDir folder. You need to periodically look through this folder, load new messages, and supply them to the SmtpRelay component for delivering directly to recipients' mailboxes.
Every time the Timer event occurs, the program starts the Email delivering process:
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Enabled = false;
try
{
string path = FileUtils.AddTrailingBackSlash(smtpFileHandler1.RelayDir);
string[] envelopeList = Directory.GetFiles(path, "*" +
SmtpFileHandler.EnvelopeFileExt);
foreach (string env in envelopeList)
{
string[] envelope = File.ReadAllLines(env);
if (envelope.Length < 2) continue;
smtpRelay1.MailFrom = envelope[0];
smtpRelay1.MailToList = ExtractRelayTo(envelope);
string msg = Path.ChangeExtension(env, SmtpFileHandler.MessageFileExt);
using (Stream stream = File.OpenRead(msg))
{
smtpRelay1.MailData.LoadFromStream(stream, "");
}
smtpRelay1.Send();
File.Delete(msg);
File.Delete(env);
}
}
finally
{
timer1.Enabled = true;
}
}
private string[] ExtractRelayTo(string[] envelope)
{
string[] result = new string[envelope.Length - 1];
Array.Copy(envelope, 1, result, 0, envelope.Length - 1);
return result;
}
Have questions?
Article ID: 158, Created: March 25, 2020 at 1:09 PM, Modified: June 4, 2020 at 4:31 PM