using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Threading.Tasks; using Amazon.SecurityToken; using Amazon.SimpleEmail; using Amazon.SimpleEmail.Model; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using MimeKit; namespace Amazon.Ses.Wrapper { public class SESEmailService : ISESEmailService { private readonly ILogger _logger; private readonly IAmazonSecurityTokenService? _securityTokenService; private readonly IAmazonSimpleEmailService _sesService; private readonly SESOptions _emailOptions; public SESEmailService(IAmazonSimpleEmailService sesService, IOptions emailOptions, ILogger logger) { _logger = logger; _sesService = sesService; _emailOptions = emailOptions.Value; } public SESEmailService(IAmazonSecurityTokenService securityTokenService, IAmazonSimpleEmailService sesService, IOptions emailOptions, ILogger logger) { _logger = logger; _securityTokenService = securityTokenService; _sesService = sesService; _emailOptions = emailOptions.Value; } /// /// /// /// sends email using AWS SES Api /// /// /// /// /// /// /// /// /// public async Task SendEmailAsync(string subject, string body, bool isHtmlBody, List to, string? sender = null, List cc = null, List bcc = null) { sender = string.IsNullOrWhiteSpace(sender) ? _emailOptions.Sender : sender; var emailMessage = BuildEmailHeaders(sender, to, cc, bcc, subject); var emailBody = BuildEmailBody(body, isHtmlBody); emailMessage.Body = emailBody.ToMessageBody(); return await SendEmailAsync(emailMessage); } /// /// sends email using AWS SES Api with attachment support (file paths) /// /// to address /// cc addresses /// /// /// /// /// /// public async Task SendEmailWithAttachmentAsync(string subject, string body, bool isHtmlBody, string fileAttachmentPath, List to, string? sender = null, List cc = null, List bcc = null) { sender = string.IsNullOrWhiteSpace(sender) ? _emailOptions.Sender : sender; var emailMessage = BuildEmailHeaders(sender, to, cc, bcc, subject); var emailBody = BuildEmailBody(body, isHtmlBody); if (!string.IsNullOrEmpty(fileAttachmentPath)) { emailBody.Attachments.Add(fileAttachmentPath); } emailMessage.Body = emailBody.ToMessageBody(); return await SendEmailAsync(emailMessage); } /// /// sends email using AWS SES Api with attachment support (file streams) /// /// /// /// /// /// /// /// /// /// public async Task SendEmailWithAttachmentAsync(string subject, string body, bool isHtmlBody, string fileName, Stream fileAttachmentStream, List to, string? sender = null, List cc = null, List bcc = null) { sender = string.IsNullOrWhiteSpace(sender) ? _emailOptions.Sender : sender; var emailMessage = BuildEmailHeaders(sender, to, cc, bcc, subject); var emailBody = BuildEmailBody(body, isHtmlBody); if (fileAttachmentStream != null && !string.IsNullOrEmpty(fileName)) { emailBody.Attachments.Add(fileName, fileAttachmentStream); } emailMessage.Body = emailBody.ToMessageBody(); return await SendEmailAsync(emailMessage); } #region private-methods /// /// builds email message body /// /// /// /// private static BodyBuilder BuildEmailBody(string body, bool isHtmlBody = true) { var bodyBuilder = new BodyBuilder(); if (isHtmlBody) { bodyBuilder.HtmlBody = body; } else { bodyBuilder.TextBody = body; } return bodyBuilder; } /// /// builds email message headers /// /// /// /// /// /// /// private static MimeMessage BuildEmailHeaders(string from, IEnumerable to, IReadOnlyCollection cc, IReadOnlyCollection bcc, string subject) { var message = new MimeMessage(); message.From.Add(new MailboxAddress(string.Empty, from)); foreach (var recipient in to) { message.To.Add(new MailboxAddress(string.Empty, recipient)); } if (cc != null && cc.Any()) { foreach (var recipient in cc) { message.Cc.Add(new MailboxAddress(string.Empty, recipient)); } } if (bcc != null && bcc.Any()) { foreach (var recipient in bcc) { message.Bcc.Add(new MailboxAddress(string.Empty, recipient)); } } message.Subject = subject; return message; } /// /// sends email using AWS SES Api - using SendRawEmail method. /// /// /// private async Task SendEmailAsync(MimeMessage message) { HttpStatusCode responseCode = HttpStatusCode.OK; string responseMessageId = null; using (var memoryStream = new MemoryStream()) { await message.WriteToAsync(memoryStream); memoryStream.Position = 0; var sendRequest = new SendRawEmailRequest { RawMessage = new RawMessage(memoryStream) }; var response = await _sesService.SendRawEmailAsync(sendRequest); responseCode = response.HttpStatusCode; responseMessageId = response.MessageId; } if (responseCode == HttpStatusCode.OK) { _logger.LogInformation($"The email with message Id {responseMessageId} sent successfully to {message.To} on {DateTime.UtcNow:O}"); } else { _logger.LogError($"Failed to send email with message Id {responseMessageId} to {message.To} on {DateTime.UtcNow:O} due to {responseCode}."); } return responseCode; } #endregion } }