Closed danzuep closed 1 year ago
@staoran would you want to look at doing this? The implementation would be similar to the custom authentication function.
I don't quite understand, the Exception(ex) method accepts a delegate? Used to handle exceptions?
However this made me think of a more flexible implementation, but more complex to implement. We can define an interface, and then inherit this interface to implement the sending logic. Then use it like this:
services.AddEmailWriter<MySend>();
or
services.AddEmailWriter<MySend>(options =>
{
options.SmtpHost = "smtp.example.com";
options.SmtpPort = 587;
options.SmtpCredential.UserName = "";
//.......
});
await _writeEmail.SendAsync<MySend>();
public class MySend : IWriter
{
private readonly IServiceScope _serviceScope;
private readonly MailSenderOptions _mailOptions;
public MySend(IServiceScopeFactory scopeFactory)
{
_serviceScope = scopeFactory.CreateScope();
_mailOptions = _serviceScope.ServiceProvider.GetRequiredService<IOptions<MailSenderOptions>>().Value;
}
public IEmailWriter Write(IEmailWriter emailWriter)
{
return emailWriter
.From(_mailOptions.DefaultFrom, _mailOptions.DefaultFromName)
.To(_mailOptions.DefaultTo)
.Subject(_mailOptions.DefaultSubject)
.BodyText(logMsg.Exception.ToString());
}
}
Maybe this is a bit over-engineered, but it is really flexible and easy to reuse.
Both good ideas. There's already an Action
Here's the existing way of setting and reusing default values:
var email = smtpSender.WriteEmail
.From("from@example.com")
.Subject("Hello World")
.TryAttach("CompanyLogo.png");
await email.Copy().To("person1@example.com").SendAsync();
await email.Copy().To("person2@example.com").SendAsync();
Now I'm starting to think I should add a SaveAsDefault() method instead that stores EmailWriterOptions. This would negate the need for emailWriter.DefaultFrom as usage would be:
var email = smtpSender.WriteEmail
.From("from@example.com")
.Subject("Hello World")
.TryAttach("CompanyLogo.png")
.SaveAsDefault();
await email.To("person1@example.com").SendAsync();
await email.To("person2@example.com").SendAsync();
If you think SaveAsDefault() is a good idea do you want to try implementing it? You could copy the email template model from MailKitSimplified.Generic or MailKitSimplified.Email.
I did a preliminary test, and MailboxAddress cannot be a configuration item.
Cannot create instance of type 'MimeKit.MailboxAddress' because it has multiple public parameterized constructors.
Maybe we need to add a new class to inherit it.
This should help. I've added it and used it with SaveAsDefault, see what you think. Other properties like the email body could be added.
public static class MimeMessageConverter
{
public static MimeMessage CopyAsTemplate(this MimeMessage original)
{
var copy = new MimeMessage();
if (original.From.Count > 0)
copy.From.AddRange(original.From);
if (original.To.Count > 0)
copy.To.AddRange(original.To);
if (original.ReplyTo.Count > 0)
copy.ReplyTo.AddRange(original.ReplyTo);
if (original.Cc.Count > 0)
copy.Cc.AddRange(original.Cc);
if (original.Bcc.Count > 0)
copy.Bcc.AddRange(original.Bcc);
if (original.Sender != null)
copy.Sender = original.Sender;
copy.Subject = original.Subject;
return copy;
}
}
I did a preliminary test, and MailboxAddress cannot be a configuration item.
I see what you mean now, the configuration builder needs an empty constructor in order to be viable. A while back I made MailKitSimplified.Generic with something like this in mind, but there's a few things I want to change about it now that some time has passed. I have an uncommitted branch where I'm cleaning it up but in the meantime the existing generic email template in MailKitSimplified.Generic should work for this.
The easiest way to achieve what you want would be to add a template file path option, then if it's not null use it like this: MimeKit.MimeMessage.Load(file.FullName);
Usage could be like:
var template = smtpSender.WriteEmail
.From("from@example.com")
.Subject("Hello World")
.TryAttach("CompanyLogo.png")
.SaveTemplateAsync(emlFilePath);
await template.To("person1@example.com").SendAsync();
var writer = await smtpSender.WithTemplateAsync(emlFilePath);
await writer.To("person2@example.com").SendAsync();
I've added this to a branch but haven't tested it yet.
Good morning. Thanks for your effort, I'll try it out. Project restricted 8.0 syntax.
Thanks for picking up on that, I've made DownloadAllAttachmentsAsync compatible with netstandard2.0 now, but still haven't tested it properly so let me know how it goes.
I had a look yesterday and fixed a couple things, but looks like I made a syntax error right before pushing the changes. This works now (once I fix the last last-minute build syntax error):
var template = smtpSender.WriteEmail
.From("from@example.com")
.Subject("Hello World")
.SaveTemplate();
await template.To("person1@example.com").SendAsync();
await template.To("person2@example.com").SendAsync();
await template.SaveTemplateAsync(emlFilePath);
var writer = await smtpSender.WithTemplateAsync(emlFilePath);
await writer.To("person3@example.com").SendAsync();
I've merged what's there so far as it should all be usable, it needs more comments and unit tests but it'll do for now. Open a new ticket if you've got any other ideas :)
Add an Action Exception template to the writer. The aim is to use the "await _writeEmail.Exception(ex).SendAsync();" method directly after having set the action for it in the builder.
Similarly, check the following: