Skip to content

Commit bd875c8

Browse files
John Campion Jrgps-lasrol
andauthored
feat: support mailgun templates (#14)
* Added support for mailgun templates * Was missing template data --------- Co-authored-by: Lasse Rolstad <lasse.rolstad@glasspaper.no>
1 parent d1d3cd3 commit bd875c8

4 files changed

Lines changed: 122 additions & 36 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System.Threading.Tasks;
2+
using FluentEmail.Core;
3+
using FluentEmail.Core.Models;
4+
5+
namespace FluentEmail.Mailgun
6+
{
7+
public static class IFluentEmailExtensions
8+
{
9+
public static async Task<SendResponse> SendWithTemplateAsync(this IFluentEmail email, string templateName, object templateData)
10+
{
11+
var mailgunSender = email.Sender as IMailgunSender;
12+
return await mailgunSender.SendWithTemplateAsync(email, templateName, templateData);
13+
}
14+
}
15+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System.Threading;
2+
using System.Threading.Tasks;
3+
using FluentEmail.Core;
4+
using FluentEmail.Core.Interfaces;
5+
using FluentEmail.Core.Models;
6+
7+
namespace FluentEmail.Mailgun;
8+
9+
public interface IMailgunSender : ISender
10+
{
11+
/// <summary>
12+
/// Mailgun specific extension method that allows you to use a template instead of a message body.
13+
/// For more information, see: https://documentation.mailgun.com/en/latest/api-sending.html#sending.
14+
/// </summary>
15+
/// <param name="email">Fluent email.</param>
16+
/// <param name="templateName">Mailgun template name.</param>
17+
/// <param name="templateData">Mailgun template data.</param>
18+
/// <param name="token">Optional cancellation token.</param>
19+
/// <returns>A SendResponse object.</returns>
20+
Task<SendResponse> SendWithTemplateAsync(IFluentEmail email, string templateName, object templateData, CancellationToken? token = null);
21+
}

src/Senders/FluentEmail.Mailgun/MailgunSender.cs

Lines changed: 73 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
using FluentEmail.Core.Interfaces;
1111
using FluentEmail.Core.Models;
1212
using FluentEmail.Mailgun.HttpHelpers;
13+
using Newtonsoft.Json;
1314

1415
namespace FluentEmail.Mailgun
1516
{
16-
public class MailgunSender : ISender
17+
public class MailgunSender : IMailgunSender
1718
{
1819
private readonly string _apiKey;
1920
private readonly string _domainName;
@@ -51,46 +52,39 @@ public SendResponse Send(IFluentEmail email, CancellationToken? token = null)
5152

5253
public async Task<SendResponse> SendAsync(IFluentEmail email, CancellationToken? token = null)
5354
{
54-
var parameters = new List<KeyValuePair<string, string>>();
55-
56-
parameters.Add(new KeyValuePair<string, string>("from", $"{email.Data.FromAddress.Name} <{email.Data.FromAddress.EmailAddress}>"));
57-
email.Data.ToAddresses.ForEach(x => {
58-
parameters.Add(new KeyValuePair<string, string>("to", $"{x.Name} <{x.EmailAddress}>"));
59-
});
60-
email.Data.CcAddresses.ForEach(x => {
61-
parameters.Add(new KeyValuePair<string, string>("cc", $"{x.Name} <{x.EmailAddress}>"));
62-
});
63-
email.Data.BccAddresses.ForEach(x => {
64-
parameters.Add(new KeyValuePair<string, string>("bcc", $"{x.Name} <{x.EmailAddress}>"));
65-
});
66-
email.Data.ReplyToAddresses.ForEach(x => {
67-
parameters.Add(new KeyValuePair<string, string>("h:Reply-To", $"{x.Name} <{x.EmailAddress}>"));
68-
});
69-
parameters.Add(new KeyValuePair<string, string>("subject", email.Data.Subject));
70-
55+
var parameters = BuildMailgunParameters(email);
56+
7157
parameters.Add(new KeyValuePair<string, string>(email.Data.IsHtml ? "html" : "text", email.Data.Body));
7258

7359
if (!string.IsNullOrEmpty(email.Data.PlaintextAlternativeBody))
7460
{
7561
parameters.Add(new KeyValuePair<string, string>("text", email.Data.PlaintextAlternativeBody));
7662
}
63+
64+
var files = BuildMailgunFiles(email);
7765

78-
email.Data.Tags.ForEach(x =>
79-
{
80-
parameters.Add(new KeyValuePair<string, string>("o:tag", x));
81-
});
66+
return await SendAsync(parameters, files, token);
67+
}
8268

83-
foreach (var emailHeader in email.Data.Headers)
84-
{
85-
var key = emailHeader.Key;
86-
if (!key.StartsWith("h:"))
87-
{
88-
key = "h:" + emailHeader.Key;
89-
}
69+
private async Task<SendResponse> SendAsync(List<KeyValuePair<string, string>> parameters, List<HttpFile> files, CancellationToken? token = null)
70+
{
71+
token?.ThrowIfCancellationRequested();
72+
73+
var response = await _httpClient.PostMultipart<MailgunResponse>("messages", parameters, files)
74+
.ConfigureAwait(false);
9075

91-
parameters.Add(new KeyValuePair<string, string>(key, emailHeader.Value));
76+
var result = new SendResponse {MessageId = response.Data?.Id};
77+
if (!response.Success)
78+
{
79+
result.ErrorMessages.AddRange(response.Errors.Select(x => x.ErrorMessage));
80+
return result;
9281
}
9382

83+
return result;
84+
}
85+
86+
private static List<HttpFile> BuildMailgunFiles(IFluentEmail email)
87+
{
9488
var files = new List<HttpFile>();
9589
email.Data.Attachments.ForEach(x =>
9690
{
@@ -109,17 +103,60 @@ public async Task<SendResponse> SendAsync(IFluentEmail email, CancellationToken?
109103
ContentType = x.ContentType
110104
});
111105
});
106+
return files;
107+
}
108+
109+
private static List<KeyValuePair<string, string>> BuildMailgunParameters(IFluentEmail email)
110+
{
111+
var parameters = new List<KeyValuePair<string, string>>();
112+
113+
parameters.Add(new KeyValuePair<string, string>("from",
114+
$"{email.Data.FromAddress.Name} <{email.Data.FromAddress.EmailAddress}>"));
115+
116+
email.Data.ToAddresses.ForEach(x =>
117+
{
118+
parameters.Add(new KeyValuePair<string, string>("to", $"{x.Name} <{x.EmailAddress}>"));
119+
});
120+
email.Data.CcAddresses.ForEach(x =>
121+
{
122+
parameters.Add(new KeyValuePair<string, string>("cc", $"{x.Name} <{x.EmailAddress}>"));
123+
});
124+
email.Data.BccAddresses.ForEach(x =>
125+
{
126+
parameters.Add(new KeyValuePair<string, string>("bcc", $"{x.Name} <{x.EmailAddress}>"));
127+
});
128+
email.Data.ReplyToAddresses.ForEach(x =>
129+
{
130+
parameters.Add(new KeyValuePair<string, string>("h:Reply-To", $"{x.Name} <{x.EmailAddress}>"));
131+
});
132+
parameters.Add(new KeyValuePair<string, string>("subject", email.Data.Subject));
112133

113-
var response = await _httpClient.PostMultipart<MailgunResponse>("messages", parameters, files).ConfigureAwait(false);
134+
email.Data.Tags.ForEach(x => { parameters.Add(new KeyValuePair<string, string>("o:tag", x)); });
114135

115-
var result = new SendResponse {MessageId = response.Data?.Id};
116-
if (!response.Success)
136+
foreach (var emailHeader in email.Data.Headers)
117137
{
118-
result.ErrorMessages.AddRange(response.Errors.Select(x => x.ErrorMessage));
119-
return result;
138+
var key = emailHeader.Key;
139+
if (!key.StartsWith("h:"))
140+
{
141+
key = "h:" + emailHeader.Key;
142+
}
143+
144+
parameters.Add(new KeyValuePair<string, string>(key, emailHeader.Value));
120145
}
146+
147+
return parameters;
148+
}
121149

122-
return result;
150+
public async Task<SendResponse> SendWithTemplateAsync(IFluentEmail email, string templateName, object templateData,
151+
CancellationToken? token = null)
152+
{
153+
var parameters = BuildMailgunParameters(email);
154+
var files = BuildMailgunFiles(email);
155+
156+
parameters.Add(new KeyValuePair<string, string>("template", templateName));
157+
parameters.Add(new KeyValuePair<string, string>("h:X-Mailgun-Variables", JsonConvert.SerializeObject(templateData)));
158+
159+
return await SendAsync(parameters, files, token);
123160
}
124161
}
125162
}

test/FluentEmail.Core.Tests/MailgunSenderTests.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,19 @@ public async Task CanSendEmailWithInlineImages()
134134
Assert.IsTrue(response.Successful);
135135
}
136136
}
137+
138+
// [Test]
139+
// public async Task CanSendEmailWithTemplate()
140+
// {
141+
// var email = Email
142+
// .From(fromEmail)
143+
// .To(toEmail)
144+
// .Subject(subject);
145+
//
146+
// var response = await email.SendWithTemplateAsync("test-template", new { var1 = "Test" });
147+
//
148+
// Assert.IsTrue(response.Successful);
149+
// }
137150

138151
class Variable
139152
{

0 commit comments

Comments
 (0)