Change implementation of the Smtp server (#3202)

* Change implementation of the Smtp server

* Update BTCPayServer/Services/Mails/EmailSettings.cs

Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>

Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>
This commit is contained in:
Nicolas Dorier 2021-12-15 21:30:46 +09:00 committed by GitHub
parent ece5401121
commit ac099aa513
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 61 additions and 60 deletions

View file

@ -2724,7 +2724,6 @@ namespace BTCPayServer.Tests
Password = "admin@admin.com",
Port = 1234,
Server = "admin.com",
EnableSSL = true
});
Assert.Equal("admin@admin.com",(await Assert.IsType<ServerEmailSender>(await emailSenderFactory.GetEmailSender()).GetEmailSettings()).Login);
Assert.Equal("admin@admin.com",(await Assert.IsType<StoreEmailSender>(await emailSenderFactory.GetEmailSender(acc.StoreId)).GetEmailSettings()).Login);
@ -2739,8 +2738,7 @@ namespace BTCPayServer.Tests
Login = "store@store.com",
Password = "store@store.com",
Port = 1234,
Server = "store.com",
EnableSSL = true
Server = "store.com"
}), ""));
Assert.Equal("store@store.com",(await Assert.IsType<StoreEmailSender>(await emailSenderFactory.GetEmailSender(acc.StoreId)).GetEmailSettings()).Login);

View file

@ -56,6 +56,7 @@
<PackageReference Include="Fido2.AspNet" Version="2.0.1" />
<PackageReference Include="HtmlSanitizer" Version="5.0.372" />
<PackageReference Include="LNURL" Version="0.0.15" />
<PackageReference Include="MailKit" Version="3.0.0" />
<PackageReference Include="McMaster.NETCore.Plugins.Mvc" Version="1.4.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Filter" Version="1.1.2" />
<PackageReference Include="Microsoft.NetCore.Analyzers" Version="3.3.2">

View file

@ -32,6 +32,7 @@ using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MimeKit;
using NBitcoin;
using NBitcoin.DataEncoders;
using Renci.SshNet;
@ -1025,10 +1026,11 @@ namespace BTCPayServer.Controllers
TempData[WellKnownTempData.ErrorMessage] = "Required fields missing";
return View(model);
}
using (var client = model.Settings.CreateSmtpClient())
using (var message = model.Settings.CreateMailMessage(new MailAddress(model.TestEmail), "BTCPay test", "BTCPay test"))
using (var client = await model.Settings.CreateSmtpClient())
using (var message = model.Settings.CreateMailMessage(new MailboxAddress(model.TestEmail, model.TestEmail), "BTCPay test", "BTCPay test", false))
{
await client.SendMailAsync(message);
await client.SendAsync(message);
await client.DisconnectAsync(true);
}
TempData[WellKnownTempData.SuccessMessage] = "Email sent to " + model.TestEmail + ", please, verify you received it";
}

View file

@ -5,6 +5,7 @@ using BTCPayServer.Data;
using BTCPayServer.Models.ServerViewModels;
using BTCPayServer.Services.Mails;
using Microsoft.AspNetCore.Mvc;
using MimeKit;
namespace BTCPayServer.Controllers
{
@ -41,9 +42,10 @@ namespace BTCPayServer.Controllers
TempData[WellKnownTempData.ErrorMessage] = "Required fields missing";
return View(model);
}
var client = model.Settings.CreateSmtpClient();
var message = model.Settings.CreateMailMessage(new MailAddress(model.TestEmail), "BTCPay test", "BTCPay test");
await client.SendMailAsync(message);
using var client = await model.Settings.CreateSmtpClient();
var message = model.Settings.CreateMailMessage(new MailboxAddress(model.TestEmail, model.TestEmail), "BTCPay test", "BTCPay test", false);
await client.SendAsync(message);
await client.DisconnectAsync(true);
TempData[WellKnownTempData.SuccessMessage] = "Email sent to " + model.TestEmail + ", please, verify you received it";
}
catch (Exception ex)

View file

@ -3,6 +3,7 @@ using System.Net.Mail;
using System.Threading.Tasks;
using BTCPayServer.Logging;
using Microsoft.Extensions.Logging;
using MimeKit;
using NBitcoin;
namespace BTCPayServer.Services.Mails
@ -29,18 +30,11 @@ namespace BTCPayServer.Services.Mails
Logs.Configuration.LogWarning("Should have sent email, but email settings are not configured");
return;
}
using (var smtp = emailSettings.CreateSmtpClient())
using (var smtp = await emailSettings.CreateSmtpClient())
{
var mail = emailSettings.CreateMailMessage(new MailAddress(email), subject, message);
mail.IsBodyHtml = true;
try
{
await smtp.SendMailAsync(mail).WithCancellation(cancellationToken);
}
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
{
smtp.SendAsyncCancel();
}
var mail = emailSettings.CreateMailMessage(new MailboxAddress(email, email), subject, message, true);
await smtp.SendAsync(mail, cancellationToken);
await smtp.DisconnectAsync(true, cancellationToken);
}
}, TimeSpan.Zero);
}

View file

@ -1,7 +1,10 @@
using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Net.Mail;
using Newtonsoft.Json;
using MailKit.Net.Smtp;
using MimeKit;
using System.Threading.Tasks;
using System.Threading;
namespace BTCPayServer.Services.Mails
{
@ -41,42 +44,47 @@ namespace BTCPayServer.Services.Mails
get; set;
}
[Display(Name = "Enable SSL")]
public bool EnableSSL
{
get; set;
}
public bool IsComplete()
{
return !string.IsNullOrWhiteSpace(Server) &&
Port is int &&
!string.IsNullOrWhiteSpace(Login) &&
!string.IsNullOrWhiteSpace(Password);
}
public MimeMessage CreateMailMessage(MailboxAddress to, string subject, string message, bool isHtml)
{
var bodyBuilder = new BodyBuilder();
if (isHtml)
{
bodyBuilder.HtmlBody = message;
}
else
{
bodyBuilder.TextBody = message;
}
return new MimeMessage(
from : new[] { new MailboxAddress(From, !string.IsNullOrWhiteSpace(FromDisplay) ? From : FromDisplay) },
to: new[] { to },
subject,
bodyBuilder.ToMessageBody());
}
public async Task<SmtpClient> CreateSmtpClient()
{
SmtpClient client = new SmtpClient();
using var connectCancel = new CancellationTokenSource(10000);
try
{
using var smtp = CreateSmtpClient();
return true;
await client.ConnectAsync(Server, Port.Value, MailKit.Security.SecureSocketOptions.Auto, connectCancel.Token);
await client.AuthenticateAsync(Login, Password, connectCancel.Token);
}
catch { }
return false;
catch
{
client.Dispose();
throw;
}
public MailMessage CreateMailMessage(MailAddress to, string subject, string message)
{
return new MailMessage(
from: new MailAddress(From, FromDisplay),
to: to)
{
Subject = subject,
Body = message
};
}
public SmtpClient CreateSmtpClient()
{
SmtpClient client = new SmtpClient(Server, Port.Value);
client.EnableSsl = EnableSSL;
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential(Login, Password);
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.Timeout = 10000;
return client;
}
}

View file

@ -9,11 +9,11 @@
Quick Fill
</button>
<div class="dropdown-menu" aria-labelledby="QuickFillDropdownToggle">
<a class="dropdown-item" href="" data-server="smtp.gmail.com" data-port="587" data-enablessl="true">Gmail.com</a>
<a class="dropdown-item" href="" data-server="mail.yahoo.com" data-port="587" data-enablessl="true">Yahoo.com</a>
<a class="dropdown-item" href="" data-server="smtp.mailgun.org" data-port="587" data-enablessl="true">Mailgun</a>
<a class="dropdown-item" href="" data-server="smtp.office365.com" data-port="587" data-enablessl="true">Office365</a>
<a class="dropdown-item" href="" data-server="smtp.sendgrid.net" data-port="587" data-enablessl="true">SendGrid</a>
<a class="dropdown-item" href="" data-server="smtp.gmail.com" data-port="587">Gmail.com</a>
<a class="dropdown-item" href="" data-server="mail.yahoo.com" data-port="587">Yahoo.com</a>
<a class="dropdown-item" href="" data-server="smtp.mailgun.org" data-port="587">Mailgun</a>
<a class="dropdown-item" href="" data-server="smtp.office365.com" data-port="587">Office365</a>
<a class="dropdown-item" href="" data-server="smtp.sendgrid.net" data-port="587">SendGrid</a>
</div>
</div>
</div>
@ -75,10 +75,6 @@
</div>
}
</div>
<div class="form-group">
<label asp-for="Settings.EnableSSL" class="form-label"></label>
<input asp-for="Settings.EnableSSL" type="checkbox" data-fill="enablessl" class="btcpay-toggle ms-2" />
</div>
<input asp-for="PasswordSet" type="hidden"/>
<button type="submit" class="btn btn-primary" name="command" value="Save">Save</button>
</div>