Added SmtpMail implementation.

pull/279/head
Halil İbrahim Kalkan 8 years ago
parent e3261f22ec
commit c52d192374

@ -15,6 +15,7 @@
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Core\Volo.Abp.Core.csproj" />
<ProjectReference Include="..\Volo.Abp.Settings\Volo.Abp.Settings.csproj" />
</ItemGroup>
</Project>

@ -1,5 +1,6 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
using Volo.Abp.Settings;
namespace Volo.Abp.Emailing
{
@ -7,6 +8,11 @@ namespace Volo.Abp.Emailing
{
public override void ConfigureServices(IServiceCollection services)
{
services.Configure<SettingOptions>(options =>
{
options.DefinitionProviders.Add<EmailSettingProvider>();
});
services.AddAssemblyOf<AbpEmailingModule>();
}
}

@ -0,0 +1,121 @@
using System;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;
namespace Volo.Abp.Emailing
{
/// <summary>
/// This class can be used as base to implement <see cref="IEmailSender"/>.
/// </summary>
public abstract class EmailSenderBase : IEmailSender
{
public IEmailSenderConfiguration Configuration { get; }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="configuration">Configuration</param>
protected EmailSenderBase(IEmailSenderConfiguration configuration)
{
Configuration = configuration;
}
public virtual async Task SendAsync(string to, string subject, string body, bool isBodyHtml = true)
{
await SendAsync(new MailMessage
{
To = { to },
Subject = subject,
Body = body,
IsBodyHtml = isBodyHtml
});
}
public virtual void Send(string to, string subject, string body, bool isBodyHtml = true)
{
Send(new MailMessage
{
To = { to },
Subject = subject,
Body = body,
IsBodyHtml = isBodyHtml
});
}
public virtual async Task SendAsync(string from, string to, string subject, string body, bool isBodyHtml = true)
{
await SendAsync(new MailMessage(from, to, subject, body) { IsBodyHtml = isBodyHtml });
}
public virtual void Send(string from, string to, string subject, string body, bool isBodyHtml = true)
{
Send(new MailMessage(from, to, subject, body) { IsBodyHtml = isBodyHtml });
}
public virtual async Task SendAsync(MailMessage mail, bool normalize = true)
{
if (normalize)
{
NormalizeMail(mail);
}
await SendEmailAsync(mail);
}
public virtual void Send(MailMessage mail, bool normalize = true)
{
if (normalize)
{
NormalizeMail(mail);
}
SendEmail(mail);
}
/// <summary>
/// Should implement this method to send email in derived classes.
/// </summary>
/// <param name="mail">Mail to be sent</param>
protected abstract Task SendEmailAsync(MailMessage mail);
/// <summary>
/// Should implement this method to send email in derived classes.
/// </summary>
/// <param name="mail">Mail to be sent</param>
protected abstract void SendEmail(MailMessage mail);
/// <summary>
/// Normalizes given email.
/// Fills <see cref="MailMessage.From"/> if it's not filled before.
/// Sets encodings to UTF8 if they are not set before.
/// </summary>
/// <param name="mail">Mail to be normalized</param>
protected virtual void NormalizeMail(MailMessage mail)
{
if (mail.From == null || mail.From.Address.IsNullOrEmpty())
{
mail.From = new MailAddress(
Configuration.DefaultFromAddress,
Configuration.DefaultFromDisplayName,
Encoding.UTF8
);
}
if (mail.HeadersEncoding == null)
{
mail.HeadersEncoding = Encoding.UTF8;
}
if (mail.SubjectEncoding == null)
{
mail.SubjectEncoding = Encoding.UTF8;
}
if (mail.BodyEncoding == null)
{
mail.BodyEncoding = Encoding.UTF8;
}
}
}
}

@ -0,0 +1,43 @@
using System;
using Volo.Abp.Settings;
namespace Volo.Abp.Emailing
{
/// <summary>
/// Implementation of <see cref="IEmailSenderConfiguration"/> that reads settings
/// from <see cref="ISettingManager"/>.
/// </summary>
public abstract class EmailSenderConfiguration : IEmailSenderConfiguration
{
public virtual string DefaultFromAddress => GetNotEmptySettingValue(EmailSettingNames.DefaultFromAddress);
public virtual string DefaultFromDisplayName => SettingManager.GetOrNull(EmailSettingNames.DefaultFromDisplayName);
protected readonly ISettingManager SettingManager;
/// <summary>
/// Creates a new <see cref="EmailSenderConfiguration"/>.
/// </summary>
protected EmailSenderConfiguration(ISettingManager settingManager)
{
SettingManager = settingManager;
}
/// <summary>
/// Gets a setting value by checking. Throws <see cref="AbpException"/> if it's null or empty.
/// </summary>
/// <param name="name">Name of the setting</param>
/// <returns>Value of the setting</returns>
protected string GetNotEmptySettingValue(string name)
{
var value = SettingManager.GetOrNull(name);
if (value.IsNullOrEmpty())
{
throw new AbpException($"Setting value for '{name}' is null or empty!");
}
return value;
}
}
}

@ -0,0 +1,59 @@
namespace Volo.Abp.Emailing
{
/// <summary>
/// Declares names of the settings defined by <see cref="EmailSettingProvider"/>.
/// </summary>
public static class EmailSettingNames
{
/// <summary>
/// Abp.Net.Mail.DefaultFromAddress
/// </summary>
public const string DefaultFromAddress = "Abp.Net.Mail.DefaultFromAddress";
/// <summary>
/// Abp.Net.Mail.DefaultFromDisplayName
/// </summary>
public const string DefaultFromDisplayName = "Abp.Net.Mail.DefaultFromDisplayName";
/// <summary>
/// SMTP related email settings.
/// </summary>
public static class Smtp
{
/// <summary>
/// Abp.Net.Mail.Smtp.Host
/// </summary>
public const string Host = "Abp.Net.Mail.Smtp.Host";
/// <summary>
/// Abp.Net.Mail.Smtp.Port
/// </summary>
public const string Port = "Abp.Net.Mail.Smtp.Port";
/// <summary>
/// Abp.Net.Mail.Smtp.UserName
/// </summary>
public const string UserName = "Abp.Net.Mail.Smtp.UserName";
/// <summary>
/// Abp.Net.Mail.Smtp.Password
/// </summary>
public const string Password = "Abp.Net.Mail.Smtp.Password";
/// <summary>
/// Abp.Net.Mail.Smtp.Domain
/// </summary>
public const string Domain = "Abp.Net.Mail.Smtp.Domain";
/// <summary>
/// Abp.Net.Mail.Smtp.EnableSsl
/// </summary>
public const string EnableSsl = "Abp.Net.Mail.Smtp.EnableSsl";
/// <summary>
/// Abp.Net.Mail.Smtp.UseDefaultCredentials
/// </summary>
public const string UseDefaultCredentials = "Abp.Net.Mail.Smtp.UseDefaultCredentials";
}
}
}

@ -0,0 +1,26 @@
using Volo.Abp.Settings;
namespace Volo.Abp.Emailing
{
/// <summary>
/// Defines settings to send emails.
/// <see cref="EmailSettingNames"/> for all available configurations.
/// </summary>
internal class EmailSettingProvider : SettingDefinitionProvider
{
public override void Define(ISettingDefinitionContext context)
{
context.Add(
new SettingDefinition(EmailSettingNames.Smtp.Host, "127.0.0.1"),
new SettingDefinition(EmailSettingNames.Smtp.Port, "25"),
new SettingDefinition(EmailSettingNames.Smtp.UserName),
new SettingDefinition(EmailSettingNames.Smtp.Password),
new SettingDefinition(EmailSettingNames.Smtp.Domain),
new SettingDefinition(EmailSettingNames.Smtp.EnableSsl, "false"),
new SettingDefinition(EmailSettingNames.Smtp.UseDefaultCredentials, "true"),
new SettingDefinition(EmailSettingNames.DefaultFromAddress),
new SettingDefinition(EmailSettingNames.DefaultFromDisplayName)
);
}
}
}

@ -0,0 +1,51 @@
using System.Net.Mail;
using System.Threading.Tasks;
namespace Volo.Abp.Emailing
{
/// <summary>
/// This service can be used simply sending emails.
/// </summary>
public interface IEmailSender
{
/// <summary>
/// Sends an email.
/// </summary>
Task SendAsync(string to, string subject, string body, bool isBodyHtml = true);
/// <summary>
/// Sends an email.
/// </summary>
void Send(string to, string subject, string body, bool isBodyHtml = true);
/// <summary>
/// Sends an email.
/// </summary>
Task SendAsync(string from, string to, string subject, string body, bool isBodyHtml = true);
/// <summary>
/// Sends an email.
/// </summary>
void Send(string from, string to, string subject, string body, bool isBodyHtml = true);
/// <summary>
/// Sends an email.
/// </summary>
/// <param name="mail">Mail to be sent</param>
/// <param name="normalize">
/// Should normalize email?
/// If true, it sets sender address/name if it's not set before and makes mail encoding UTF-8.
/// </param>
void Send(MailMessage mail, bool normalize = true);
/// <summary>
/// Sends an email.
/// </summary>
/// <param name="mail">Mail to be sent</param>
/// <param name="normalize">
/// Should normalize email?
/// If true, it sets sender address/name if it's not set before and makes mail encoding UTF-8.
/// </param>
Task SendAsync(MailMessage mail, bool normalize = true);
}
}

@ -0,0 +1,18 @@
namespace Volo.Abp.Emailing
{
/// <summary>
/// Defines configurations used while sending emails.
/// </summary>
public interface IEmailSenderConfiguration
{
/// <summary>
/// Default from address.
/// </summary>
string DefaultFromAddress { get; }
/// <summary>
/// Default display name.
/// </summary>
string DefaultFromDisplayName { get; }
}
}

@ -0,0 +1,49 @@
using System.Net.Mail;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Volo.Abp.Emailing
{
/// <summary>
/// This class is an implementation of <see cref="IEmailSender"/> as similar to null pattern.
/// It does not send emails but logs them.
/// </summary>
public class NullEmailSender : EmailSenderBase
{
public ILogger<NullEmailSender> Logger { get; set; }
/// <summary>
/// Creates a new <see cref="NullEmailSender"/> object.
/// </summary>
/// <param name="configuration">Configuration</param>
public NullEmailSender(IEmailSenderConfiguration configuration)
: base(configuration)
{
Logger = NullLogger<NullEmailSender>.Instance;
}
protected override Task SendEmailAsync(MailMessage mail)
{
Logger.LogWarning("USING NullEmailSender!");
Logger.LogDebug("SendEmailAsync:");
LogEmail(mail);
return Task.FromResult(0);
}
protected override void SendEmail(MailMessage mail)
{
Logger.LogWarning("USING NullEmailSender!");
Logger.LogWarning("SendEmail:");
LogEmail(mail);
}
private void LogEmail(MailMessage mail)
{
Logger.LogDebug(mail.To.ToString());
Logger.LogDebug(mail.CC.ToString());
Logger.LogDebug(mail.Subject);
Logger.LogDebug(mail.Body);
}
}
}

@ -0,0 +1,18 @@
using System.Net.Mail;
namespace Volo.Abp.Emailing.Smtp
{
/// <summary>
/// Used to send emails over SMTP.
/// </summary>
public interface ISmtpEmailSender : IEmailSender
{
/// <summary>
/// Creates and configures new <see cref="SmtpClient"/> object to send emails.
/// </summary>
/// <returns>
/// An <see cref="SmtpClient"/> object that is ready to send emails.
/// </returns>
SmtpClient BuildClient();
}
}

@ -0,0 +1,43 @@
namespace Volo.Abp.Emailing.Smtp
{
/// <summary>
/// Defines configurations to used by SmtpClient object.
/// </summary>
public interface ISmtpEmailSenderConfiguration : IEmailSenderConfiguration
{
/// <summary>
/// SMTP Host name/IP.
/// </summary>
string Host { get; }
/// <summary>
/// SMTP Port.
/// </summary>
int Port { get; }
/// <summary>
/// User name to login to SMTP server.
/// </summary>
string UserName { get; }
/// <summary>
/// Password to login to SMTP server.
/// </summary>
string Password { get; }
/// <summary>
/// Domain name to login to SMTP server.
/// </summary>
string Domain { get; }
/// <summary>
/// Is SSL enabled?
/// </summary>
bool EnableSsl { get; }
/// <summary>
/// Use default credentials?
/// </summary>
bool UseDefaultCredentials { get; }
}
}

@ -0,0 +1,83 @@
using System;
using System.Net;
using System.Net.Mail;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Emailing.Smtp
{
/// <summary>
/// Used to send emails over SMTP.
/// </summary>
public class SmtpEmailSender : EmailSenderBase, ISmtpEmailSender, ITransientDependency
{
private readonly ISmtpEmailSenderConfiguration _configuration;
/// <summary>
/// Creates a new <see cref="SmtpEmailSender"/>.
/// </summary>
/// <param name="configuration">Configuration</param>
public SmtpEmailSender(ISmtpEmailSenderConfiguration configuration)
: base(configuration)
{
_configuration = configuration;
}
public SmtpClient BuildClient()
{
var host = _configuration.Host;
var port = _configuration.Port;
var smtpClient = new SmtpClient(host, port);
try
{
if (_configuration.EnableSsl)
{
smtpClient.EnableSsl = true;
}
if (_configuration.UseDefaultCredentials)
{
smtpClient.UseDefaultCredentials = true;
}
else
{
smtpClient.UseDefaultCredentials = false;
var userName = _configuration.UserName;
if (!userName.IsNullOrEmpty())
{
var password = _configuration.Password;
var domain = _configuration.Domain;
smtpClient.Credentials = !domain.IsNullOrEmpty()
? new NetworkCredential(userName, password, domain)
: new NetworkCredential(userName, password);
}
}
return smtpClient;
}
catch
{
smtpClient.Dispose();
throw;
}
}
protected override async Task SendEmailAsync(MailMessage mail)
{
using (var smtpClient = BuildClient())
{
await smtpClient.SendMailAsync(mail);
}
}
protected override void SendEmail(MailMessage mail)
{
using (var smtpClient = BuildClient())
{
smtpClient.Send(mail);
}
}
}
}

@ -0,0 +1,33 @@
using System;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
namespace Volo.Abp.Emailing.Smtp
{
/// <summary>
/// Implementation of <see cref="ISmtpEmailSenderConfiguration"/> that reads settings
/// from <see cref="ISettingManager"/>.
/// </summary>
public class SmtpEmailSenderConfiguration : EmailSenderConfiguration, ISmtpEmailSenderConfiguration, ITransientDependency
{
public virtual string Host => GetNotEmptySettingValue(EmailSettingNames.Smtp.Host);
public virtual int Port => GetNotEmptySettingValue(EmailSettingNames.Smtp.Port).To<int>();
public virtual string UserName => GetNotEmptySettingValue(EmailSettingNames.Smtp.UserName);
public virtual string Password => GetNotEmptySettingValue(EmailSettingNames.Smtp.Password);
public virtual string Domain => SettingManager.GetOrNull(EmailSettingNames.Smtp.Domain);
public virtual bool EnableSsl => SettingManager.GetOrNull(EmailSettingNames.Smtp.EnableSsl).To<bool>();
public virtual bool UseDefaultCredentials => SettingManager.GetOrNull(EmailSettingNames.Smtp.UseDefaultCredentials).To<bool>();
public SmtpEmailSenderConfiguration(ISettingManager settingManager)
: base(settingManager)
{
}
}
}

@ -1,8 +1,23 @@
namespace Volo.Abp.Settings
using System.Collections.Generic;
using JetBrains.Annotations;
using Volo.Abp.Threading;
namespace Volo.Abp.Settings
{
public static class SettingManagerSyncExtensions
{
//TODO: Add sync extension methods for all setting manager methods.
//TODO: Also add sync extension methods for all value provider extensions (like GlobalSettingManagerExtensions).
public static string GetOrNull([NotNull] this ISettingManager settingManager, [NotNull] string name)
{
Check.NotNull(settingManager, nameof(settingManager));
return AsyncHelper.RunSync(() => settingManager.GetOrNullAsync(name));
}
public static List<SettingValue> GetAll([NotNull] this ISettingManager settingManager)
{
Check.NotNull(settingManager, nameof(settingManager));
return AsyncHelper.RunSync(settingManager.GetAllAsync);
}
}
}

Loading…
Cancel
Save