https://nuget.org/packages/NServiceBus.Mailer/
PM> Install-Package NServiceBus.Mailer
var configuration = new BusConfiguration();
configuration.EndpointName("NServiceBusMailSample");
var mailerSettings = configuration.EnableMailer();
MailSender
can be resolved from the container.
public class MyHandler : IHandleMessages<MyMessage>
{
MailSender mailSender;
public MyHandler(MailSender mailSender)
{
this.mailSender = mailSender;
}
public void Handle(MyMessage message)
{
var mail = new Mail
{
To = "to@fake.email",
From = "from@fake.email",
Body = "This is the body",
Subject = "Hello",
};
mailSender.SendMail(mail);
}
}
The interface ISmtpBuilder
can be used to control how an SmtpClient
is constructed.
By default the DefaultSmtpBuilder
will be used. This effectively uses the code
return new SmtpClient
{
EnableSsl = true
};
This results in the SmtpClient
defaulting to reading its settings from the application config.
To create a custom ISmtpBuilder
take the following actions.
To have your own custom SmtpClient
simply inherit from ISmtpBuilder
.
public class ToDirectorySmtpBuilder : ISmtpBuilder
{
public SmtpClient BuildClient()
{
var directoryLocation = Path.Combine(Environment.CurrentDirectory, "Emails");
Directory.CreateDirectory(directoryLocation);
return new SmtpClient
{
DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory,
PickupDirectoryLocation = directoryLocation
};
}
}
Then configure your builder.
var mailerSettings = configuration.EnableMailer();
mailerSettings.UseSmtpBuilder<ToDirectorySmtpBuilder>();
Since it is not practical to send binary data as part of messages there is an alternative mechanism. The interface IAttachmentFinder
can be used to defer attachment creation until the point of the email being sent.
// attachmentContext will be the same dictionary you passed in on Mail.AttachmentContext when calling BusExtensions.SendMail.
public class AttachmentFinder : IAttachmentFinder
{
public IEnumerable<Attachment> FindAttachments(Dictionary<string, string> attachmentContext)
{
// Find the Attachments for the given context.
var id = attachmentContext["Id"];
var memoryStream = new MemoryStream(Encoding.ASCII.GetBytes("Hello"));
yield return new Attachment(memoryStream, "example.txt", "text/plain");
}
public void CleanAttachments(Dictionary<string, string> attachmentContext)
{
// Attachment cleanup can be performed here
}
}
Then configure your attachment folder.
var mailerSettings = configuration.EnableMailer();
mailerSettings.UseAttachmentFinder<AttachmentFinder>();
Pass an AttachmentContext
when calling SendMail
. The AttachmentContext
should contain enough information for you to derive how to find and return the attachments for the email.
var mail = new Mail
{
To = "to@fake.email",
From = "from@fake.email",
Body = "This is the body",
Subject = "Hello",
AttachmentContext = new Dictionary<string, string>{{"Id","fakeEmail"}}
};
bus.SendMail(mail);
Retrying email is difficult due to the fact that when sending an email to multiple addresses a subset of those addresses may return an error. In this case re-sending to all addresses would result in some addresses receiving the email multiple times.
This case is when there is a generic exception talking to the mail server or the server returns an error that indicates all addresses have failed.
This is handling by letting the exception bubble to NServiceBus. This will result in falling back on the standard NServiceBus retry logic.
This will most likely occur when there is a subset of invalid addresses however there cases where the address can fail once and succeed after a retry. Have a look at SmtpStatusCode for the possible error cases.
In this scenario it is not valid to retry the message since it would result in the message being resent to all recipients. It is also flawed to resend the verbatim email to the subset of failed addresses as this would effectively exclude them from some of the recipients in the conversation.
So the approach taken is to forward the original message to the failed recipients after prefixing the body with the following text
This message was forwarded due to the original email failing to send
-----Original Message-----
To: XXX
CC: XXX
Sent: XXX
While this is a little hacky it achieves the desired of letting the failed recipients receive the email contents while also notifying them that there is a conversation happening with other recipients. It also avoids spamming the other recipients.
Envelope designed by Herbert Spencer from The Noun Project