Sphyrnidae Common Library
2.0.1
Shared Utilities/Library
|
Sending an email is the purpose of the IEmail interface. To access this, you should likely utilize the wrapper as this allows for lots of overloads against the interface. There is only 1 method on the interface, so your chosen implementation could be as simple as you'd like. However, we recommend a great deal of configurability which is present in our implementation (and is easily applied to your custom implementation).
Interface: IEmail
Mock: EmailMock
Wrapper: Email
Implementations:
The DotNetEmail is very configurable. There are many principles at work here, so we'll start with the EmailType. This implementation also makes use of IEmailSettings and IDotNetEmailSettings. An email is generally made up of the following pieces of information:
3-7 are provided via the interface (will be up to the consumer of this interface to specify all of these). It should be up to your implementation to fill in 1-2, make any changes to the others, format the body, and actually send the message.
Knowing the type of email, allows you to hard-code certain things. These "things", in the implementation, are the actual listing of recipients (eg. To). This allows you to have a configurable list of recipients per email type.
The IEmailSettings interface allows for all of the customizations. There are several "Recipients" properties that will be the "To" listing of email address matching up with the corresponding type:
Email Type | Property |
---|---|
Exception | ExceptionsRecipients |
HiddenException | HiddenExceptionRecipients |
Logging | LoggingRecipients |
LongRunning | LongRunningRecipients |
HttpFailure | HttpFailureRecipients |
Custom | User-supplied during the call |
Redirects are the ability to change who the email is being sent to (or cc/bcc). A redirect could happen for any number of reasons, but the most common scenario is environment-specific. In a non-production environment, you want to make sure that emails are not actually being sent out to end-users. You can guard against this by having the following configurations retrieve their values from the environment or from variables.
The remaining properties will also need to be filled in:
In my implementations, I have these filled in by another interface implementation: IEmailDefaultSettings
The last piece of configurability is specific to the DotNetEmail implementation. This implementation uses the IDotNetEmailSettings to specify customizations that are specific for sending emails in .Net. Hopefully these properties are self-explanatory, and please note the Password property is encrypted.
If you are developing your own implementation of sending emails, you may wish to utilize this same type of behavior. The EmailHelper class can help apply all of these behaviors to your interface implementation. From there, it will be your responsibility in your implementation to take everything from the EmailItems and put this data into your email object.
public class DotNetEmail : IEmail { private IEmailSettings Settings { get; } private IDotNetEmailSettings DotNetSettings { get; } private IEncryption Encryption { get; } public DotNetEmail(IEmailSettings settings, IDotNetEmailSettings dotNetSettings, IEncryption encryption) { Settings = settings; DotNetSettings = dotNetSettings; Encryption = encryption; } public async Task<bool> SendAsync(EmailType type, IEnumerable<string> to, IEnumerable<string> cc, string subject, string content) { var emailInformation = EmailHelper.ToEmailItems(Settings, type, to, cc, subject, content); var msg = new MailMessage { From = new MailAddress(emailInformation.FromEmail, emailInformation.FromName), Subject = emailInformation.Subject }; foreach (var email in emailInformation.To) msg.To.Add(new MailAddress(email)); foreach (var email in emailInformation.Cc) msg.CC.Add(new MailAddress(email)); foreach (var email in emailInformation.Bcc) msg.Bcc.Add(new MailAddress(email)); msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(emailInformation.Body, null, MediaTypeNames.Text.Plain)); msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(emailInformation.Body.ToHtml(), null, MediaTypeNames.Text.Html)); using var client = new SmtpClient { DeliveryMethod = SmtpDeliveryMethod.Network, EnableSsl = DotNetSettings.EnableSsl }; var host = DotNetSettings.Host; if (!string.IsNullOrWhiteSpace(host)) client.Host = host; var port = DotNetSettings.Port; if (port.HasValue && port.Value != 0) client.Port = port.Value; var password = DotNetSettings.Password; if (!string.IsNullOrWhiteSpace(password)) { client.UseDefaultCredentials = false; var decrypted = password.Decrypt(Encryption).Value; client.Credentials = new NetworkCredential(emailInformation.FromEmail, decrypted); } // Must leave as try/catch because the client would otherwise be disposed and not captured try { await client.SendMailAsync(msg); return true; } catch (Exception ex) { return false; } } }