diff --git a/samples/GeekLearning.Email.Samples/Controllers/HomeController.cs b/samples/GeekLearning.Email.Samples/Controllers/HomeController.cs index 4218548..8f8544a 100644 --- a/samples/GeekLearning.Email.Samples/Controllers/HomeController.cs +++ b/samples/GeekLearning.Email.Samples/Controllers/HomeController.cs @@ -22,19 +22,33 @@ public IActionResult Index() public async Task SendEmail() { - var user = new User + + EmailAddress toAddress1 = new EmailAddress() { Email = "rhsmith@gworld.com", DisplayName = "Bob" }; + EmailAddress toAddress2 = new EmailAddress() { Email = "sammy.davis@null.com", DisplayName = "Sam" }; + + // example of how to add a simple attachment. Add images, streams, etc as byte arrays, for example: + + MimeKit.AttachmentCollection attachments = new MimeKit.AttachmentCollection { - Email = "john@doe.me", - DisplayName = "John Doe" + { "sample_attachment.txt", System.Text.Encoding.UTF8.GetBytes("This is the content of the file attachment.") } }; + + + await this.emailSender.SendEmailAsync(new EmailAddress() { Email="from.somebody@domain.tld", DisplayName="Me" }, "A simple message","This is a test message", attachments, toAddress1); + + + // Here is a second send example. No attachments, but using templates. Specifies to send a Cc to ccRecipient, using a decorator: + + IEmailAddress ccRecipient = new EmailAddress() { Email = "myfriend@somewhere.com", DisplayName = "Joe Smith" }; + var context = new { ApplicationName = "Email Sender Sample", - User = user + User = toAddress1 }; + await this.emailSender.SendTemplatedEmailAsync("Invitation", context, toAddress2, ccRecipient.ToCc() ); - await this.emailSender.SendTemplatedEmailAsync("Invitation", context, user); return RedirectToAction("Index"); } diff --git a/src/GeekLearning.Email.InMemory/InMemoryEmailProvider.cs b/src/GeekLearning.Email.InMemory/InMemoryEmailProvider.cs index fea5443..c7f1953 100644 --- a/src/GeekLearning.Email.InMemory/InMemoryEmailProvider.cs +++ b/src/GeekLearning.Email.InMemory/InMemoryEmailProvider.cs @@ -12,8 +12,14 @@ public InMemoryEmailProvider(IEmailProviderOptions options, IInMemoryEmailReposi { this.inMemoryEmailRepository = inMemoryEmailRepository; } - + + // for compatibility: public Task SendEmailAsync(IEmailAddress from, IEnumerable recipients, string subject, string text, string html) + { + return this.SendEmailAsync(from, recipients, subject, text, html, null); + } + + public Task SendEmailAsync(IEmailAddress from, IEnumerable recipients, string subject, string text, string html, MimeKit.AttachmentCollection attachments) { this.inMemoryEmailRepository.Save(new InMemoryEmail { diff --git a/src/GeekLearning.Email.SendGrid/SendGridEmailProvider.cs b/src/GeekLearning.Email.SendGrid/SendGridEmailProvider.cs index 37da7d5..b7b8766 100644 --- a/src/GeekLearning.Email.SendGrid/SendGridEmailProvider.cs +++ b/src/GeekLearning.Email.SendGrid/SendGridEmailProvider.cs @@ -28,7 +28,8 @@ public async Task SendEmailAsync( IEnumerable recipients, string subject, string text, - string html) + string html, + MimeKit.AttachmentCollection attachments) { var client = new SendGridClient(this.apiKey); diff --git a/src/GeekLearning.Email.Smtp/SmtpEmailProvider.cs b/src/GeekLearning.Email.Smtp/SmtpEmailProvider.cs index f5ef0bb..c9f269e 100644 --- a/src/GeekLearning.Email.Smtp/SmtpEmailProvider.cs +++ b/src/GeekLearning.Email.Smtp/SmtpEmailProvider.cs @@ -1,11 +1,12 @@ namespace GeekLearning.Email.Smtp { - using MailKit.Net.Smtp; + using MailKit.Net.Smtp; using MailKit.Security; using MimeKit; using System; using System.Collections.Generic; using System.Threading.Tasks; + using Internal; public class SmtpEmailProvider : IEmailProvider { @@ -37,13 +38,38 @@ public async Task SendEmailAsync( IEnumerable recipients, string subject, string text, - string html) + string html, + AttachmentCollection attachments) { var message = new MimeMessage(); message.From.Add(new MailboxAddress(from.DisplayName, from.Email)); foreach (var recipient in recipients) { - message.To.Add(new MailboxAddress(recipient.DisplayName, recipient.Email)); + InternetAddress address = new MailboxAddress(recipient.DisplayName, recipient.Email); + if (recipient is EmailAddressExt) + { + var recip = recipient as Internal.EmailAddressExt; + switch (recip.AddressAs) + { + case AddressTarget.Cc: + message.Cc.Add(address); + break; + case AddressTarget.Bcc: + message.Bcc.Add(address); + break; + case AddressTarget.ReplyTo: + message.ReplyTo.Add(address); + break; + default: + message.To.Add(address); + break; + } + } + else + { + message.To.Add(address); + } + } message.Subject = subject; @@ -51,9 +77,16 @@ public async Task SendEmailAsync( var builder = new BodyBuilder { TextBody = text, - HtmlBody = html + HtmlBody = html, }; - + builder.Attachments.Clear(); + if (attachments != null) + { + foreach (var attachment in attachments) + { + builder.Attachments.Add(attachment); + } + } message.Body = builder.ToMessageBody(); using (var client = new SmtpClient()) diff --git a/src/GeekLearning.Email/IEmailAddress.cs b/src/GeekLearning.Email/IEmailAddress.cs index 992d0de..172477b 100644 --- a/src/GeekLearning.Email/IEmailAddress.cs +++ b/src/GeekLearning.Email/IEmailAddress.cs @@ -1,4 +1,4 @@ -namespace GeekLearning.Email +namespace GeekLearning.Email { public interface IEmailAddress { diff --git a/src/GeekLearning.Email/IEmailProvider.cs b/src/GeekLearning.Email/IEmailProvider.cs index a505895..9a5b231 100644 --- a/src/GeekLearning.Email/IEmailProvider.cs +++ b/src/GeekLearning.Email/IEmailProvider.cs @@ -1,11 +1,18 @@ -namespace GeekLearning.Email +namespace GeekLearning.Email { using System.Collections.Generic; using System.Threading.Tasks; - + using MimeKit; + public interface IEmailProvider { - Task SendEmailAsync(IEmailAddress from, IEnumerable recipients, string subject, string bodyText, string bodyHtml); + Task SendEmailAsync( + IEmailAddress from, + IEnumerable recipients, + string subject, + string bodyText, + string bodyHtml + AttachmentCollection attachments=null); } } diff --git a/src/GeekLearning.Email/IEmailSender.cs b/src/GeekLearning.Email/IEmailSender.cs index f5d0820..664c9d6 100644 --- a/src/GeekLearning.Email/IEmailSender.cs +++ b/src/GeekLearning.Email/IEmailSender.cs @@ -4,12 +4,20 @@ public interface IEmailSender { + Task SendEmailAsync(string subject, string message, AttachmentCollection attachments, params IEmailAddress[] to); + Task SendEmailAsync(string subject, string message, params IEmailAddress[] to); Task SendEmailAsync(IEmailAddress from, string subject, string message, params IEmailAddress[] to); + Task SendEmailAsync(IEmailAddress from, string subject, string message, AttachmentCollection attachments, params IEmailAddress[] to); + + Task SendTemplatedEmailAsync(string templateKey, T context, AttachmentCollection attachments, params IEmailAddress[] to); + Task SendTemplatedEmailAsync(string templateKey, T context, params IEmailAddress[] to); Task SendTemplatedEmailAsync(IEmailAddress from, string templateKey, T context, params IEmailAddress[] to); + + Task SendTemplatedEmailAsync(IEmailAddress from, string templateKey, T context, AttachmentCollection attachments, params IEmailAddress[] to); } } diff --git a/src/GeekLearning.Email/Internal/EmailAddress.cs b/src/GeekLearning.Email/Internal/EmailAddress.cs index 2654f82..0ed5342 100644 --- a/src/GeekLearning.Email/Internal/EmailAddress.cs +++ b/src/GeekLearning.Email/Internal/EmailAddress.cs @@ -1,7 +1,10 @@ namespace GeekLearning.Email.Internal { + public enum AddressTarget { Cc, Bcc, ReplyTo } + public class EmailAddress : IEmailAddress { + public EmailAddress() { } @@ -15,5 +18,44 @@ public EmailAddress(string email, string displayName) public string Email { get; set; } public string DisplayName { get; set; } + + } + + public class EmailAddressExt : IEmailAddress + { + private IEmailAddress _emailAddress {get; set;} + + public EmailAddressExt(IEmailAddress emailAddress) : base() { + this._emailAddress = emailAddress; + } + + public string Email { + get { return this._emailAddress.Email; } + } + + public string DisplayName { + get { return this._emailAddress.DisplayName; } + } + + public AddressTarget AddressAs { get; set; } + } + + public static class EmailAddressExtensions + { + + public static EmailAddressExt ToCc(this IEmailAddress emailAddress) + { + return new EmailAddressExt(emailAddress) { AddressAs = AddressTarget.Cc }; + } + + public static EmailAddressExt ToBcc(this IEmailAddress emailAddress) + { + return new EmailAddressExt(emailAddress) { AddressAs = AddressTarget.Bcc }; + } + + public static EmailAddressExt ToReplyTo(this IEmailAddress emailAddress) + { + return new EmailAddressExt(emailAddress) { AddressAs = AddressTarget.ReplyTo }; + } } } diff --git a/src/GeekLearning.Email/Internal/EmailSender.cs b/src/GeekLearning.Email/Internal/EmailSender.cs index 5aa2895..d9e9d64 100644 --- a/src/GeekLearning.Email/Internal/EmailSender.cs +++ b/src/GeekLearning.Email/Internal/EmailSender.cs @@ -43,19 +43,34 @@ public EmailSender( } } + public Task SendEmailAsync(string subject, string message, MimeKit.AttachmentCollection attachments, params IEmailAddress[] to) + { + return this.SendEmailAsync(options.DefaultSender, subject, message, attachments, to); + } + public Task SendEmailAsync(string subject, string message, params IEmailAddress[] to) { - return this.SendEmailAsync(options.DefaultSender, subject, message, to); + return this.SendEmailAsync(options.DefaultSender, subject, message, null, to); } public Task SendEmailAsync(IEmailAddress from, string subject, string message, params IEmailAddress[] to) + { + return this.SendEmailAsync(from, subject, message, null, to); + } + + public Task SendEmailAsync(IEmailAddress from, string subject, string message, MimeKit.AttachmentCollection attachments, params IEmailAddress[] to) { return DoMockupAndSendEmailAsync( from, to, subject, message, - string.Format("
{0}", message)); + string.Format("
{0}", message), attachments); + } + + public Task SendTemplatedEmailAsync(string templateKey, T context, MimeKit.AttachmentCollection attachments, params IEmailAddress[] to) + { + return this.SendTemplatedEmailAsync(options.DefaultSender, templateKey, context, attachments, to); } public Task SendTemplatedEmailAsync(string templateKey, T context, params IEmailAddress[] to) @@ -74,7 +89,25 @@ await this.DoMockupAndSendEmailAsync( to, subjectTemplate.Apply(context), textTemplate.Apply(context), - htmlTemplate.Apply(context)); + htmlTemplate.Apply(context), + null + ); + } + + public async Task SendTemplatedEmailAsync(IEmailAddress from, string templateKey, T context, MimeKit.AttachmentCollection attachments, params IEmailAddress[] to) + { + var subjectTemplate = await this.GetTemplateAsync(templateKey, EmailTemplateType.Subject); + var textTemplate = await this.GetTemplateAsync(templateKey, EmailTemplateType.BodyText); + var htmlTemplate = await this.GetTemplateAsync(templateKey, EmailTemplateType.BodyHtml); + + await this.DoMockupAndSendEmailAsync( + from, + to, + subjectTemplate.Apply(context), + textTemplate.Apply(context), + htmlTemplate.Apply(context), + attachments + ); } private Task GetTemplateAsync(string templateKey, EmailTemplateType templateType) @@ -84,10 +117,11 @@ private Task GetTemplateAsync(string templateKey, EmailTemplateType t private async Task DoMockupAndSendEmailAsync( IEmailAddress from, - IEnumerable recipients, + IEmailAddress [] recipients, string subject, string text, - string html) + string html, + MimeKit.AttachmentCollection attachments) { var finalRecipients = new List(); var mockedUpRecipients = new List(); @@ -96,15 +130,12 @@ private async Task DoMockupAndSendEmailAsync( { foreach (var recipient in recipients) { - var emailParts = recipient.Email.Split('@'); - if (emailParts.Length != 2) - { - throw new NotSupportedException("Bad recipient email."); - } - + string trimmedEmail = recipient.Email.Trim(); + + var emailParts = trimmedEmail.Split('@'); var domain = emailParts[1]; - if (!this.options.Mockup.Exceptions.Emails.Contains(recipient.Email) + if (!this.options.Mockup.Exceptions.Emails.Contains(trimmedEmail) && !this.options.Mockup.Exceptions.Domains.Contains(domain)) { if (!mockedUpRecipients.Any()) @@ -142,7 +173,7 @@ await this.provider.SendEmailAsync( finalRecipients, subject, text, - html); + html, attachments); } } } diff --git a/tests/GeekLearning.Email.Integration.Test/SendTemplatedTest.cs b/tests/GeekLearning.Email.Integration.Test/SendTemplatedTest.cs index 5ae7ec4..5fb3bc7 100644 --- a/tests/GeekLearning.Email.Integration.Test/SendTemplatedTest.cs +++ b/tests/GeekLearning.Email.Integration.Test/SendTemplatedTest.cs @@ -55,17 +55,12 @@ public async Task SendNotification1(string storeName) new SendGrid.SendGridEmailProviderType(), }; - var emailSender = new Internal.EmailSender( - providerTypes, - options, - this.storeFixture.Services.GetRequiredService(), - this.storeFixture.Services.GetRequiredService()); + IEmailAddress address = new Internal.EmailAddress() { + DisplayName = "test user", + Email = "no-reply@test.geeklearning.io" + }; - await emailSender.SendTemplatedEmailAsync("Notification1", new { }, new Internal.EmailAddress - { - DisplayName = "test user", - Email = "no-reply@test.geeklearning.io" - }); + await emailSender.SendTemplatedEmailAsync("Notification1", new { }, address); } } }