-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add EmailSender abstraction for sending mails using either SMTP or Ma…
…ilgun (#293) This PR adds an `IEmailSender` abstraction along with implementations `SmtpEmailSender` and `MailgunEmailSender`, and refactors `EmailService` to use said abstraction. The main idea is to allow for local email testing using an SMTP server such as [MailHog](https://github.com/mailhog/MailHog), which has also been added to the Docker Compose configuration. <img width="1494" alt="image" src="https://github.com/user-attachments/assets/99e86a78-02eb-4e82-bcb8-da70192f6667">
- Loading branch information
Showing
8 changed files
with
108 additions
and
31 deletions.
There are no files selected for viewing
11 changes: 11 additions & 0 deletions
11
coffeecard/CoffeeCard.Common/Configuration/SmtpSettings.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using System.ComponentModel.DataAnnotations; | ||
|
||
namespace CoffeeCard.Common.Configuration | ||
{ | ||
public class SmtpSettings | ||
{ | ||
[Required] public string Host { get; set; } | ||
[Required] public int Port { get; set; } | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,13 +18,13 @@ public class EmailService : IEmailService | |
{ | ||
private readonly IWebHostEnvironment _env; | ||
private readonly EnvironmentSettings _environmentSettings; | ||
private readonly MailgunSettings _mailgunSettings; | ||
private readonly IEmailSender _emailSender; | ||
private readonly IMapperService _mapperService; | ||
|
||
public EmailService(MailgunSettings mailgunSettings, EnvironmentSettings environmentSettings, | ||
public EmailService(IEmailSender emailSender, EnvironmentSettings environmentSettings, | ||
IWebHostEnvironment env, IMapperService mapperService) | ||
{ | ||
_mailgunSettings = mailgunSettings; | ||
_emailSender = emailSender; | ||
_environmentSettings = environmentSettings; | ||
_env = env; | ||
_mapperService = mapperService; | ||
|
@@ -54,7 +54,7 @@ public async Task SendInvoiceAsync(UserDto user, PurchaseDto purchase) | |
|
||
Log.Information("Sending invoice for PurchaseId {PurchaseId} to UserId {UserId}, E-mail {Email}", purchase.Id, user.Id, user.Email); | ||
|
||
await SendEmailAsync(message); | ||
await _emailSender.SendEmailAsync(message); | ||
} | ||
|
||
public async Task SendRegistrationVerificationEmailAsync(User user, string token) | ||
|
@@ -71,7 +71,7 @@ public async Task SendRegistrationVerificationEmailAsync(User user, string token | |
|
||
message.Body = builder.ToMessageBody(); | ||
|
||
await SendEmailAsync(message); | ||
await _emailSender.SendEmailAsync(message); | ||
} | ||
|
||
public async Task SendVerificationEmailForLostPwAsync(User user, string token) | ||
|
@@ -87,7 +87,7 @@ public async Task SendVerificationEmailForLostPwAsync(User user, string token) | |
|
||
message.Body = builder.ToMessageBody(); | ||
|
||
await SendEmailAsync(message); | ||
await _emailSender.SendEmailAsync(message); | ||
} | ||
|
||
public async Task SendVerificationEmailForDeleteAccount(User user, string token) | ||
|
@@ -104,7 +104,7 @@ public async Task SendVerificationEmailForDeleteAccount(User user, string token) | |
|
||
message.Body = builder.ToMessageBody(); | ||
|
||
await SendEmailAsync(message); | ||
await _emailSender.SendEmailAsync(message); | ||
} | ||
|
||
public async Task SendInvoiceAsyncV2(Purchase purchase, User user) | ||
|
@@ -150,29 +150,5 @@ private BodyBuilder RetrieveTemplate(string templateName) | |
|
||
return builder; | ||
} | ||
|
||
private async Task SendEmailAsync(MimeMessage mail) | ||
{ | ||
var client = new RestClient(_mailgunSettings.MailgunApiUrl) | ||
{ | ||
Authenticator = new HttpBasicAuthenticator("api", _mailgunSettings.ApiKey) | ||
}; | ||
|
||
var request = new RestRequest(); | ||
request.AddParameter("domain", _mailgunSettings.Domain, ParameterType.UrlSegment); | ||
request.Resource = "{domain}/messages"; | ||
request.AddParameter("from", "Cafe Analog <[email protected]>"); | ||
request.AddParameter("to", mail.To[0].ToString()); | ||
request.AddParameter("subject", mail.Subject); | ||
request.AddParameter("html", mail.HtmlBody); | ||
request.Method = Method.Post; | ||
|
||
var response = await client.ExecutePostAsync(request); | ||
|
||
if (!response.IsSuccessful) | ||
{ | ||
Log.Error("Error sending request to Mailgun. StatusCode: {statusCode} ErrorMessage: {errorMessage}", response.StatusCode, response.ErrorMessage); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
using System.Threading.Tasks; | ||
using MimeKit; | ||
|
||
namespace CoffeeCard.Library.Services; | ||
|
||
public interface IEmailSender | ||
{ | ||
public Task SendEmailAsync(MimeMessage email); | ||
} |
34 changes: 34 additions & 0 deletions
34
coffeecard/CoffeeCard.Library/Services/MailgunEmailSender.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
using System.Threading.Tasks; | ||
using CoffeeCard.Common.Configuration; | ||
using MimeKit; | ||
using RestSharp; | ||
using RestSharp.Authenticators; | ||
using Serilog; | ||
|
||
namespace CoffeeCard.Library.Services; | ||
|
||
public class MailgunEmailSender(MailgunSettings mailgunSettings) : IEmailSender | ||
{ | ||
public async Task SendEmailAsync(MimeMessage mail) | ||
{ | ||
using var client = new RestClient(mailgunSettings.MailgunApiUrl); | ||
client.Authenticator = new HttpBasicAuthenticator("api", mailgunSettings.ApiKey); | ||
|
||
var request = new RestRequest(); | ||
request.AddParameter("domain", mailgunSettings.Domain, ParameterType.UrlSegment); | ||
request.Resource = "{domain}/messages"; | ||
request.AddParameter("from", "Cafe Analog <[email protected]>"); | ||
request.AddParameter("to", mail.To[0].ToString()); | ||
request.AddParameter("subject", mail.Subject); | ||
request.AddParameter("html", mail.HtmlBody); | ||
request.Method = Method.Post; | ||
|
||
var response = await client.ExecutePostAsync(request); | ||
|
||
if (!response.IsSuccessful) | ||
{ | ||
Log.Error("Error sending request to Mailgun. StatusCode: {statusCode} ErrorMessage: {errorMessage}", | ||
response.StatusCode, response.ErrorMessage); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
using CoffeeCard.Common.Configuration; | ||
using MailKit.Net.Smtp; | ||
using MimeKit; | ||
using Serilog; | ||
|
||
namespace CoffeeCard.Library.Services; | ||
|
||
public class SmtpEmailSender(SmtpSettings smtpSettings) : IEmailSender | ||
{ | ||
public async Task SendEmailAsync(MimeMessage mail) | ||
{ | ||
mail.From.Add(new MailboxAddress("Cafe Analog", "[email protected]")); | ||
|
||
try | ||
{ | ||
using var smtpClient = new SmtpClient(); | ||
await smtpClient.ConnectAsync(smtpSettings.Host, smtpSettings.Port); | ||
await smtpClient.SendAsync(mail); | ||
await smtpClient.DisconnectAsync(true); | ||
} | ||
catch (Exception ex) | ||
{ | ||
Log.Error("Error sending request to SMTP server. Error: {errorMessage}", ex.Message); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters