Mailgun integration

master
Tudor Stanciu 2023-01-21 04:05:14 +02:00
parent 9cf25aff19
commit 35124b515d
13 changed files with 173 additions and 7 deletions

View File

@ -32,6 +32,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Correo.MailKit", "src\Corre
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Correo.SendGrid", "src\Correo.SendGrid\Correo.SendGrid.csproj", "{1457426A-CD47-4201-BE3C-A40B38FCB1FA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Correo.Mailgun", "src\Correo.Mailgun\Correo.Mailgun.csproj", "{78DC392D-B24A-43CA-B632-6124CD2C35B1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
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}.Release|Any CPU.ActiveCfg = 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
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -83,6 +89,7 @@ Global
{ED8048DC-8509-4085-97F0-F9D9A59A689A} = {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}
{78DC392D-B24A-43CA-B632-6124CD2C35B1} = {245E2FBE-DFDF-40B4-94B7-5DDA216E58AD}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {86FCF989-26FC-41E9-8A23-9485606D619D}

View File

@ -10,5 +10,6 @@
<NBBPackageVersion>6.0.30</NBBPackageVersion>
<MailKitPackageVersion>3.4.3</MailKitPackageVersion>
<SendGridPackageVersion>9.28.1</SendGridPackageVersion>
<RestSharpPackageVersion>108.0.3</RestSharpPackageVersion>
</PropertyGroup>
</Project>

View File

@ -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>

View File

@ -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>();
}
}
}

View File

@ -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()));
}
}
}

View File

@ -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()};");
}
}

View File

@ -0,0 +1,8 @@
namespace Correo.Mailgun.Models
{
internal record MailgunOptions
{
public string ApiKey { get; init; }
public string Domain { get; init; }
}
}

View File

@ -0,0 +1,8 @@
namespace Correo.Mailgun.Models
{
public record MailgunResponse
{
public string Id { get; init; }
public string Message { get; init; }
}
}

View File

@ -0,0 +1 @@
Docs: https://documentation.mailgun.com/en/latest/api-sending.html#sending

View File

@ -28,9 +28,7 @@ namespace Correo.SendGrid
public void SendEmail(EmailMessage message)
{
var mailMessage = message.ToSendGridMessage();
_client.SendEmailAsync(mailMessage).GetAwaiter().GetResult();
Log(message);
SendEmailAsync(message).GetAwaiter().GetResult();
}
public async Task SendEmailAsync(EmailMessage message, CancellationToken token = default)

View File

@ -16,6 +16,7 @@
<ItemGroup>
<ProjectReference Include="..\Correo.Application\Correo.Application.csproj" />
<ProjectReference Include="..\Correo.Mailgun\Correo.Mailgun.csproj" />
<ProjectReference Include="..\Correo.MailKit\Correo.MailKit.csproj" />
<ProjectReference Include="..\Correo.NetSmtpClient\Correo.NetSmtpClient.csproj" />
<ProjectReference Include="..\Correo.SendGrid\Correo.SendGrid.csproj" />

View File

@ -1,4 +1,5 @@
using Correo.MailKit;
using Correo.Mailgun;
using Correo.MailKit;
using Correo.NetSmtpClient;
using Correo.SendGrid;
using Microsoft.Extensions.Configuration;
@ -22,7 +23,11 @@ namespace Correo.Extensions
}
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
{

View File

@ -29,7 +29,7 @@
"Address": "noreply@homelab.com",
"Name": "HomeLab"
},
"SmtpMediator": ".NET", //.NET, MailKit, SendGrid
"SmtpMediator": ".NET", //.NET, MailKit, SendGrid, Mailgun
"SmtpClient": {
"Server": "smtp.gmail.com",
"Port": "587",
@ -42,7 +42,11 @@
"EnableSsl": true,
"TrustServer": false
},
"SmtpService": {
"SendGrid": {
"ApiKey": "xxxxxxxxxxx"
},
"Mailgun": {
"ApiKey": "xxxxxxxxxxx",
"Domain": "xxxxxxxxxxx"
}
}