-
Notifications
You must be signed in to change notification settings - Fork 3
gl-dotnet-email changes for Cc, Bcc, ReplyTo, and attachments #33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 10 commits
2ae944b
6a9a2fc
28b5117
52d1bcb
b241f9a
35d7331
36618ae
08fb23e
d9198ab
2a1cf73
9635f2a
19bbf69
3d2e989
b5dbc89
2e4b9e1
90d4f8d
2493e33
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,13 @@ | ||
| namespace GeekLearning.Email | ||
| namespace GeekLearning.Email | ||
| { | ||
| public enum AddressTarget { From, To, Cc, Bcc, ReplyTo} | ||
|
|
||
| public interface IEmailAddress | ||
| { | ||
| string Email { get; } | ||
|
|
||
| string DisplayName { get; } | ||
|
|
||
| AddressTarget AddressAs { get; } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<IEmailAddress> recipients, string subject, string bodyText, string bodyHtml); | ||
| Task SendEmailAsync( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My idea was to be able to define a complete email transaction in one call. You might want to send to two (or more) different addresses, Cc: another, and Bcc: yet another, and also have a ReplyTo: for the message that is different that the From: address. (some hosting services required the From address to match the authentication user name, which might not be the same as the 'sender' of the immediate message). Using an attribute parameter for the email address implies a single target transaction. Slower if the app wants to send to several targets. |
||
| IEmailAddress from, | ||
| IEnumerable<IEmailAddress> recipients, | ||
| string subject, | ||
| string bodyText, | ||
| string bodyHtml | ||
| AttachmentCollection attachments=null); | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,12 +4,12 @@ | |
|
|
||
| public interface IEmailSender | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there should be additional overloads using
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a thought. But there needs to be a solid way to link an AddressTarget to an email address. And how does it look if we have multiple email addresses in the call? |
||
| { | ||
| Task SendEmailAsync(string subject, string message, params IEmailAddress[] to); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should not remove the params commodity. |
||
| Task SendEmailAsync(string subject, string message, IEnumerable<IEmailAddress> recipients, AttachmentCollection attachments=null); | ||
|
|
||
| Task SendEmailAsync(IEmailAddress from, string subject, string message, params IEmailAddress[] to); | ||
| Task SendEmailAsync(IEmailAddress from, string subject, string message, IEnumerable<IEmailAddress> recipients, AttachmentCollection attachments=null); | ||
|
|
||
| Task SendTemplatedEmailAsync<T>(string templateKey, T context, params IEmailAddress[] to); | ||
| Task SendTemplatedEmailAsync<T>(string templateKey, T context, IEnumerable<IEmailAddress> recipients, AttachmentCollection attachments=null); | ||
|
|
||
| Task SendTemplatedEmailAsync<T>(IEmailAddress from, string templateKey, T context, params IEmailAddress[] to); | ||
| Task SendTemplatedEmailAsync<T>(IEmailAddress from, string templateKey, T context, IEnumerable<IEmailAddress> recipients, AttachmentCollection attachments=null); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,14 +6,17 @@ public EmailAddress() | |
| { | ||
| } | ||
|
|
||
| public EmailAddress(string email, string displayName) | ||
| public EmailAddress(string email, string displayName, AddressTarget addressAs=AddressTarget.To) | ||
| { | ||
| this.Email = email; | ||
| this.DisplayName = displayName; | ||
| this.AddressAs = addressAs; | ||
| } | ||
|
|
||
| public string Email { get; set; } | ||
|
|
||
| public string DisplayName { get; set; } | ||
|
|
||
| public AddressTarget AddressAs { get; set; } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we don't want that. |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,7 @@ | |
| using System.Linq; | ||
| using System.Threading.Tasks; | ||
| using Templating; | ||
| using System.Text.RegularExpressions; | ||
|
|
||
| public class EmailSender : IEmailSender | ||
| { | ||
|
|
@@ -43,27 +44,28 @@ public EmailSender( | |
| } | ||
| } | ||
|
|
||
| public Task SendEmailAsync(string subject, string message, params IEmailAddress[] to) | ||
| public Task SendEmailAsync(string subject, string message, IEnumerable<IEmailAddress> to, MimeKit.AttachmentCollection attachments) | ||
| { | ||
| return this.SendEmailAsync(options.DefaultSender, subject, message, to); | ||
| return this.SendEmailAsync(options.DefaultSender, subject, message, to, attachments); | ||
| } | ||
|
|
||
| public Task SendEmailAsync(IEmailAddress from, string subject, string message, params IEmailAddress[] to) | ||
| public Task SendEmailAsync(IEmailAddress from, string subject, string message, IEnumerable<IEmailAddress> to, MimeKit.AttachmentCollection attachments) | ||
| { | ||
| return DoMockupAndSendEmailAsync( | ||
| from, | ||
| to, | ||
| subject, | ||
| message, | ||
| string.Format("<html><header></header><body>{0}</body></html>", message)); | ||
| string.Format("<html><header></header><body>{0}</body></html>", message), | ||
| attachments); | ||
| } | ||
|
|
||
| public Task SendTemplatedEmailAsync<T>(string templateKey, T context, params IEmailAddress[] to) | ||
| public Task SendTemplatedEmailAsync<T>(string templateKey, T context, IEnumerable<IEmailAddress> to, MimeKit.AttachmentCollection attachments) | ||
| { | ||
| return this.SendTemplatedEmailAsync(options.DefaultSender, templateKey, context, to); | ||
| return this.SendTemplatedEmailAsync(options.DefaultSender, templateKey, context, to, attachments); | ||
| } | ||
|
|
||
| public async Task SendTemplatedEmailAsync<T>(IEmailAddress from, string templateKey, T context, params IEmailAddress[] to) | ||
| public async Task SendTemplatedEmailAsync<T>(IEmailAddress from, string templateKey, T context, IEnumerable<IEmailAddress> to, MimeKit.AttachmentCollection attachments) | ||
| { | ||
| var subjectTemplate = await this.GetTemplateAsync(templateKey, EmailTemplateType.Subject); | ||
| var textTemplate = await this.GetTemplateAsync(templateKey, EmailTemplateType.BodyText); | ||
|
|
@@ -74,7 +76,8 @@ await this.DoMockupAndSendEmailAsync( | |
| to, | ||
| subjectTemplate.Apply(context), | ||
| textTemplate.Apply(context), | ||
| htmlTemplate.Apply(context)); | ||
| htmlTemplate.Apply(context), | ||
| attachments); | ||
| } | ||
|
|
||
| private Task<ITemplate> GetTemplateAsync(string templateKey, EmailTemplateType templateType) | ||
|
|
@@ -87,7 +90,8 @@ private async Task DoMockupAndSendEmailAsync( | |
| IEnumerable<IEmailAddress> recipients, | ||
| string subject, | ||
| string text, | ||
| string html) | ||
| string html, | ||
| MimeKit.AttachmentCollection attachments) | ||
| { | ||
| var finalRecipients = new List<IEmailAddress>(); | ||
| var mockedUpRecipients = new List<IEmailAddress>(); | ||
|
|
@@ -96,12 +100,15 @@ private async Task DoMockupAndSendEmailAsync( | |
| { | ||
| foreach (var recipient in recipients) | ||
| { | ||
| var emailParts = recipient.Email.Split('@'); | ||
| if (emailParts.Length != 2) | ||
|
|
||
| string trimmedEmail = recipient.Email.Trim(); | ||
| // not sure if it's the most friendly to validate in the sender method. Should be left to caller code, IMO | ||
| if (Regex.IsMatch(trimmedEmail, @"\A(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\Z", RegexOptions.IgnoreCase).Equals(false)) | ||
|
||
| { | ||
| throw new NotSupportedException("Bad recipient email."); | ||
| } | ||
|
|
||
| var emailParts = trimmedEmail.Split('@'); | ||
| var domain = emailParts[1]; | ||
|
|
||
| if (!this.options.Mockup.Exceptions.Emails.Contains(recipient.Email) | ||
|
|
@@ -142,7 +149,7 @@ await this.provider.SendEmailAsync( | |
| finalRecipients, | ||
| subject, | ||
| text, | ||
| html); | ||
| html, attachments); | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IEmailAddressis meant to be a simple interface consumer can implement on their on types (or through a facade) so they can use such objects directly.I think
AddressTargetshould be an argument forIEmailSendermethods overloads, not a part of this interface.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand your idea about IEmailAddress, just defining the conventional "name user@domain.tld" definition. So, what might be an elegant way to link the email user with their 'AddressTarget' attributes? I think I was guessing your thinking when I made the AddressAs property optional. It can be left out, and will default to a 'To:' address insertion. But to avoid the original params implementation (which gets awkward if you want to define 5-10 or more recipients!), and keep the original simplicity of the IEmailAddress contract, maybe there has to have as inputs some kind of User structure, in which the IEmailAddress is itself a property? or overload the class methods? It would be nice to avoid too much of that.