Permalink
Please sign in to comment.
Showing
with
261 additions
and 10 deletions.
- +67 −0 Config/EmailsServiceOptions.cs
- +9 −1 Controllers/V1/UsersController.cs
- +8 −5 Craidd.csproj
- +34 −0 Extensions/EmailsSenderExtensions.cs
- +77 −0 Services/EmailsService.cs
- +10 −0 Services/IEmailsService.cs
- +9 −0 Services/ITemplatesService.cs
- +17 −0 Services/TemplatesService.cs
- +29 −4 Startup.cs
- +1 −0 Views/Emails/Register.cshtml
@@ -0,0 +1,67 @@ | |||
using System; | |||
using MailKit.Net.Smtp; | |||
|
|||
namespace Craidd.Config | |||
{ | |||
public class EmailsServiceOptions | |||
{ | |||
/// <summary> | |||
/// Gets or sets the name or IP Address of the host used for SMTP transactions. | |||
/// </summary> | |||
public string host { get; set; } | |||
|
|||
/// <summary> | |||
/// Gets or sets the port used for SMTP transactions. | |||
/// </summary> | |||
public int port { get; set; } = 25; | |||
|
|||
/// <summary> | |||
/// Specify whether the <see cref="SmtpClient"/> uses Secure Sockets Layer (SSL) to encrypt the connection. | |||
/// </summary> | |||
public bool useSSL { get; set; } = false; | |||
|
|||
/// <summary> | |||
/// Gets or sets the account used for SMTP transactions. | |||
/// </summary> | |||
public string username { get; set; } | |||
|
|||
/// <summary> | |||
/// Gets or sets the password used for SMTP transactions. | |||
/// </summary> | |||
public string password { get; set; } | |||
|
|||
/// <summary> | |||
/// Gets or sets the email for the from address. | |||
/// | |||
public string fromEmail { get; set; } | |||
|
|||
/// <summary> | |||
/// Gets or sets the name for the from address. | |||
/// </summary> | |||
public string fromName { get; set; } | |||
|
|||
public void Validate() | |||
{ | |||
if (string.IsNullOrWhiteSpace(host)) | |||
{ | |||
throw new ArgumentNullException(nameof(host)); | |||
} | |||
if (string.IsNullOrWhiteSpace(username)) | |||
{ | |||
throw new ArgumentNullException(nameof(username)); | |||
} | |||
if (password == null) | |||
{ | |||
throw new ArgumentNullException(nameof(password)); | |||
} | |||
if (fromName == null) | |||
{ | |||
throw new ArgumentNullException(nameof(fromName)); | |||
} | |||
if (fromEmail == null) | |||
{ | |||
throw new ArgumentNullException(nameof(fromEmail)); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,34 @@ | |||
using Craidd.Config; | |||
using Craidd.Services; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.DependencyInjection.Extensions; | |||
using System; | |||
|
|||
namespace Craidd.Extensions | |||
{ | |||
public static class EmailsSenderExtensions | |||
{ | |||
/// <summary> | |||
/// Using Email Middleware | |||
/// </summary> | |||
/// <param name="services">The <see cref="IServiceCollection"/> passed to the configuration method.</param> | |||
/// <param name="setupAction">The middleware configuration options.</param> | |||
/// <returns>The updated <see cref="IServiceCollection"/>.</returns> | |||
public static IServiceCollection AddEmail(this IServiceCollection services, Action<EmailsServiceOptions> setupAction = null) | |||
{ | |||
if (services == null) | |||
{ | |||
throw new ArgumentNullException(nameof(services)); | |||
} | |||
|
|||
if (setupAction != null) | |||
{ | |||
services.Configure(setupAction); // IOptions<EmailsServiceOptions> | |||
} | |||
|
|||
services.TryAddTransient<IEmailsService, EmailsService>(); | |||
|
|||
return services; | |||
} | |||
} | |||
} |
@@ -0,0 +1,77 @@ | |||
using System.Threading.Tasks; | |||
using System.Collections.Generic; | |||
using Microsoft.AspNetCore.Identity.UI.Services; | |||
using Microsoft.Extensions.Options; | |||
using MailKit.Net.Smtp; | |||
using MimeKit; | |||
using Craidd.Config; | |||
using System; | |||
using System.Linq; | |||
using System.Dynamic; | |||
|
|||
namespace Craidd.Services | |||
{ | |||
public class EmailsService : IEmailsService | |||
{ | |||
private readonly EmailsServiceOptions _options; | |||
private readonly ITemplatesService _templatesService; | |||
public EmailsService(IOptions<EmailsServiceOptions> optionsAccessor, ITemplatesService templatesService) | |||
{ | |||
_options = optionsAccessor?.Value ?? throw new ArgumentNullException(nameof(optionsAccessor)); | |||
_options.Validate(); | |||
_templatesService = templatesService; | |||
} | |||
|
|||
public async Task<bool> sendEmailFromTemplateAsync(string email, string subject, string templateFile, Dictionary<string, object> messageData) | |||
{ | |||
var message = new MimeMessage(); | |||
message.From.Add(new MailboxAddress(_options.fromName, _options.fromEmail)); | |||
message.To.Add(new MailboxAddress(email)); | |||
message.Subject = subject; | |||
|
|||
var localMessageData = messageData.Aggregate( | |||
new ExpandoObject() as IDictionary<string, Object>, | |||
(a, p) => { a.Add(p.Key, p.Value); return a; } | |||
); | |||
|
|||
string html = await _templatesService.engine.CompileRenderAsync($"Emails/{templateFile}.cshtml", localMessageData); | |||
message.Body = new TextPart("html") | |||
{ | |||
Text = html | |||
}; | |||
|
|||
using (var client = new SmtpClient()) | |||
{ | |||
try | |||
{ | |||
await client.ConnectAsync(_options.host, _options.port, _options.useSSL); | |||
await client.AuthenticateAsync(_options.username, _options.password); | |||
await client.SendAsync(message); | |||
} | |||
catch (SmtpCommandException ex) | |||
{ | |||
switch (ex.ErrorCode) | |||
{ | |||
case SmtpErrorCode.RecipientNotAccepted: | |||
Console.WriteLine("\tRecipient not accepted: {0}", ex.Mailbox); | |||
break; | |||
case SmtpErrorCode.SenderNotAccepted: | |||
Console.WriteLine("\tSender not accepted: {0}", ex.Mailbox); | |||
break; | |||
case SmtpErrorCode.MessageNotAccepted: | |||
Console.WriteLine("\tMessage not accepted."); | |||
break; | |||
} | |||
|
|||
return false; | |||
} | |||
finally | |||
{ | |||
await client.DisconnectAsync(true); | |||
} | |||
} | |||
|
|||
return true; | |||
} | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
using System.Collections.Generic; | |||
using System.Threading.Tasks; | |||
|
|||
namespace Craidd.Services | |||
{ | |||
public interface IEmailsService | |||
{ | |||
Task<bool> sendEmailFromTemplateAsync(string email, string subject, string templateFile, Dictionary<string, object> messageData); | |||
} | |||
} |
@@ -0,0 +1,9 @@ | |||
using RazorLight; | |||
|
|||
namespace Craidd.Services | |||
{ | |||
public interface ITemplatesService | |||
{ | |||
RazorLightEngine engine { get; set; } | |||
} | |||
} |
@@ -0,0 +1,17 @@ | |||
using System; | |||
using RazorLight; | |||
|
|||
namespace Craidd.Services | |||
{ | |||
public class TemplatesService : ITemplatesService | |||
{ | |||
public RazorLightEngine engine { get; set; } | |||
public TemplatesService(string templatePath) | |||
{ | |||
engine = new RazorLightEngineBuilder() | |||
.UseFilesystemProject(templatePath) | |||
.UseMemoryCachingProvider() | |||
.Build(); | |||
} | |||
} | |||
} |
@@ -0,0 +1 @@ | |||
<p> @Model.Name </p> |
0 comments on commit
dc6c974