Mailgun integration
parent
9cf25aff19
commit
35124b515d
|
@ -32,6 +32,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Correo.MailKit", "src\Corre
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Correo.SendGrid", "src\Correo.SendGrid\Correo.SendGrid.csproj", "{1457426A-CD47-4201-BE3C-A40B38FCB1FA}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Correo.SendGrid", "src\Correo.SendGrid\Correo.SendGrid.csproj", "{1457426A-CD47-4201-BE3C-A40B38FCB1FA}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Correo.Mailgun", "src\Correo.Mailgun\Correo.Mailgun.csproj", "{78DC392D-B24A-43CA-B632-6124CD2C35B1}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -70,6 +72,10 @@ Global
|
||||||
{1457426A-CD47-4201-BE3C-A40B38FCB1FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{1457426A-CD47-4201-BE3C-A40B38FCB1FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{1457426A-CD47-4201-BE3C-A40B38FCB1FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{1457426A-CD47-4201-BE3C-A40B38FCB1FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{1457426A-CD47-4201-BE3C-A40B38FCB1FA}.Release|Any CPU.Build.0 = Release|Any CPU
|
{1457426A-CD47-4201-BE3C-A40B38FCB1FA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{78DC392D-B24A-43CA-B632-6124CD2C35B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{78DC392D-B24A-43CA-B632-6124CD2C35B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{78DC392D-B24A-43CA-B632-6124CD2C35B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{78DC392D-B24A-43CA-B632-6124CD2C35B1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -83,6 +89,7 @@ Global
|
||||||
{ED8048DC-8509-4085-97F0-F9D9A59A689A} = {245E2FBE-DFDF-40B4-94B7-5DDA216E58AD}
|
{ED8048DC-8509-4085-97F0-F9D9A59A689A} = {245E2FBE-DFDF-40B4-94B7-5DDA216E58AD}
|
||||||
{325B77E1-D752-4578-8BF7-793905C38DCD} = {245E2FBE-DFDF-40B4-94B7-5DDA216E58AD}
|
{325B77E1-D752-4578-8BF7-793905C38DCD} = {245E2FBE-DFDF-40B4-94B7-5DDA216E58AD}
|
||||||
{1457426A-CD47-4201-BE3C-A40B38FCB1FA} = {245E2FBE-DFDF-40B4-94B7-5DDA216E58AD}
|
{1457426A-CD47-4201-BE3C-A40B38FCB1FA} = {245E2FBE-DFDF-40B4-94B7-5DDA216E58AD}
|
||||||
|
{78DC392D-B24A-43CA-B632-6124CD2C35B1} = {245E2FBE-DFDF-40B4-94B7-5DDA216E58AD}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {86FCF989-26FC-41E9-8A23-9485606D619D}
|
SolutionGuid = {86FCF989-26FC-41E9-8A23-9485606D619D}
|
||||||
|
|
|
@ -10,5 +10,6 @@
|
||||||
<NBBPackageVersion>6.0.30</NBBPackageVersion>
|
<NBBPackageVersion>6.0.30</NBBPackageVersion>
|
||||||
<MailKitPackageVersion>3.4.3</MailKitPackageVersion>
|
<MailKitPackageVersion>3.4.3</MailKitPackageVersion>
|
||||||
<SendGridPackageVersion>9.28.1</SendGridPackageVersion>
|
<SendGridPackageVersion>9.28.1</SendGridPackageVersion>
|
||||||
|
<RestSharpPackageVersion>108.0.3</RestSharpPackageVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="$(MicrosoftExtensionsPackageVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftExtensionsPackageVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="$(MicrosoftExtensionsPackageVersion)" />
|
||||||
|
<PackageReference Include="RestSharp" Version="$(RestSharpPackageVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Correo.Abstractions\Correo.Abstractions.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,16 @@
|
||||||
|
using Correo.Abstractions;
|
||||||
|
using Correo.Mailgun.Models;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Correo.Mailgun
|
||||||
|
{
|
||||||
|
public static class DependencyInjectionExtensions
|
||||||
|
{
|
||||||
|
public static void AddMailgunService(this IServiceCollection services, IConfigurationSection configuration)
|
||||||
|
{
|
||||||
|
services.Configure<MailgunOptions>(configuration);
|
||||||
|
services.AddTransient<IMailer, MailgunService>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using Correo.Abstractions;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Correo.Mailgun.Extensions
|
||||||
|
{
|
||||||
|
internal static class ModelExtensions
|
||||||
|
{
|
||||||
|
public static string ToMailgunAddress(this EmailMessage.MailAddress address)
|
||||||
|
=> $"{address.DisplayName} <{address.Address}>";
|
||||||
|
|
||||||
|
public static string ToMailgunAddresses(this IEnumerable<EmailMessage.MailAddress> addresses)
|
||||||
|
{
|
||||||
|
if (addresses == null || !addresses.Any())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return string.Join(',', addresses.Select(z => z.ToMailgunAddress()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
using Correo.Abstractions;
|
||||||
|
using Correo.Abstractions.Extensions;
|
||||||
|
using Correo.Mailgun.Extensions;
|
||||||
|
using Correo.Mailgun.Models;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using RestSharp;
|
||||||
|
using RestSharp.Authenticators;
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Correo.Mailgun
|
||||||
|
{
|
||||||
|
internal class MailgunService : IMailer, IDisposable
|
||||||
|
{
|
||||||
|
private readonly IOptions<MailgunOptions> _optionsAccessor;
|
||||||
|
private readonly RestClient _client;
|
||||||
|
private readonly ILogger<MailgunService> _logger;
|
||||||
|
|
||||||
|
public MailgunService(IOptions<MailgunOptions> optionsAccessor, ILogger<MailgunService> logger)
|
||||||
|
{
|
||||||
|
_optionsAccessor = optionsAccessor;
|
||||||
|
_logger = logger;
|
||||||
|
_client = new RestClient("https://api.mailgun.net/v3")
|
||||||
|
{
|
||||||
|
Authenticator = new HttpBasicAuthenticator("api", _optionsAccessor.Value.ApiKey)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_client.Dispose();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendEmail(EmailMessage message)
|
||||||
|
{
|
||||||
|
SendEmailAsync(message).GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SendEmailAsync(EmailMessage message, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
var request = new RestRequest();
|
||||||
|
request.AddParameter("domain", _optionsAccessor.Value.Domain, ParameterType.UrlSegment);
|
||||||
|
request.Resource = "{domain}/messages";
|
||||||
|
|
||||||
|
request.AddParameter("subject", message.Subject);
|
||||||
|
var contentKey = message.IsBodyHtml ? "html" : "text";
|
||||||
|
request.AddParameter(contentKey, message.Body);
|
||||||
|
|
||||||
|
request.AddParameter("from", message.From.ToMailgunAddress());
|
||||||
|
request.AddParameter("to", message.To.ToMailgunAddresses());
|
||||||
|
|
||||||
|
var cc = message.Cc.ToMailgunAddresses();
|
||||||
|
if (cc != null)
|
||||||
|
request.AddParameter("cc", cc);
|
||||||
|
|
||||||
|
var bcc = message.Bcc.ToMailgunAddresses();
|
||||||
|
if (bcc != null)
|
||||||
|
request.AddParameter("bcc", bcc);
|
||||||
|
|
||||||
|
request.Method = Method.Post;
|
||||||
|
var response = await _client.ExecuteAsync<MailgunResponse>(request, token);
|
||||||
|
if (response.IsSuccessful)
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Mailgun response: {response.Data.Message} {response.Data.Id}");
|
||||||
|
Log(message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception($"Mailgun error: {response.Data.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Log(EmailMessage message)
|
||||||
|
=> _logger.LogInformation($"Email sent: Subject: {message.Subject}; From: {message.From.Address}; To: {message.To.Log()}; Cc: {message.Cc.Log()}; Bcc: {message.Bcc.Log()};");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Correo.Mailgun.Models
|
||||||
|
{
|
||||||
|
internal record MailgunOptions
|
||||||
|
{
|
||||||
|
public string ApiKey { get; init; }
|
||||||
|
public string Domain { get; init; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Correo.Mailgun.Models
|
||||||
|
{
|
||||||
|
public record MailgunResponse
|
||||||
|
{
|
||||||
|
public string Id { get; init; }
|
||||||
|
public string Message { get; init; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
Docs: https://documentation.mailgun.com/en/latest/api-sending.html#sending
|
|
@ -28,9 +28,7 @@ namespace Correo.SendGrid
|
||||||
|
|
||||||
public void SendEmail(EmailMessage message)
|
public void SendEmail(EmailMessage message)
|
||||||
{
|
{
|
||||||
var mailMessage = message.ToSendGridMessage();
|
SendEmailAsync(message).GetAwaiter().GetResult();
|
||||||
_client.SendEmailAsync(mailMessage).GetAwaiter().GetResult();
|
|
||||||
Log(message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SendEmailAsync(EmailMessage message, CancellationToken token = default)
|
public async Task SendEmailAsync(EmailMessage message, CancellationToken token = default)
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Correo.Application\Correo.Application.csproj" />
|
<ProjectReference Include="..\Correo.Application\Correo.Application.csproj" />
|
||||||
|
<ProjectReference Include="..\Correo.Mailgun\Correo.Mailgun.csproj" />
|
||||||
<ProjectReference Include="..\Correo.MailKit\Correo.MailKit.csproj" />
|
<ProjectReference Include="..\Correo.MailKit\Correo.MailKit.csproj" />
|
||||||
<ProjectReference Include="..\Correo.NetSmtpClient\Correo.NetSmtpClient.csproj" />
|
<ProjectReference Include="..\Correo.NetSmtpClient\Correo.NetSmtpClient.csproj" />
|
||||||
<ProjectReference Include="..\Correo.SendGrid\Correo.SendGrid.csproj" />
|
<ProjectReference Include="..\Correo.SendGrid\Correo.SendGrid.csproj" />
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Correo.MailKit;
|
using Correo.Mailgun;
|
||||||
|
using Correo.MailKit;
|
||||||
using Correo.NetSmtpClient;
|
using Correo.NetSmtpClient;
|
||||||
using Correo.SendGrid;
|
using Correo.SendGrid;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
@ -22,7 +23,11 @@ namespace Correo.Extensions
|
||||||
}
|
}
|
||||||
else if (mediator.Equals("SendGrid", StringComparison.InvariantCultureIgnoreCase))
|
else if (mediator.Equals("SendGrid", StringComparison.InvariantCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
services.AddSendGridService(configuration.GetSection("SmtpService"));
|
services.AddSendGridService(configuration.GetSection("SendGrid"));
|
||||||
|
}
|
||||||
|
else if (mediator.Equals("Mailgun", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
services.AddMailgunService(configuration.GetSection("Mailgun"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
"Address": "noreply@homelab.com",
|
"Address": "noreply@homelab.com",
|
||||||
"Name": "HomeLab"
|
"Name": "HomeLab"
|
||||||
},
|
},
|
||||||
"SmtpMediator": ".NET", //.NET, MailKit, SendGrid
|
"SmtpMediator": ".NET", //.NET, MailKit, SendGrid, Mailgun
|
||||||
"SmtpClient": {
|
"SmtpClient": {
|
||||||
"Server": "smtp.gmail.com",
|
"Server": "smtp.gmail.com",
|
||||||
"Port": "587",
|
"Port": "587",
|
||||||
|
@ -42,7 +42,11 @@
|
||||||
"EnableSsl": true,
|
"EnableSsl": true,
|
||||||
"TrustServer": false
|
"TrustServer": false
|
||||||
},
|
},
|
||||||
"SmtpService": {
|
"SendGrid": {
|
||||||
"ApiKey": "xxxxxxxxxxx"
|
"ApiKey": "xxxxxxxxxxx"
|
||||||
|
},
|
||||||
|
"Mailgun": {
|
||||||
|
"ApiKey": "xxxxxxxxxxx",
|
||||||
|
"Domain": "xxxxxxxxxxx"
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue