1. 程式人生 > >結合ABP原始碼實現郵件傳送功能

結合ABP原始碼實現郵件傳送功能

1. 前言

最近pm臨時提出了多種郵件驗證操作的需求,因為一時間也沒有找到好的郵件收發元件,也抱著研究ABP的心態,就花了幾小時時間探究了一下ABP中關於Email的處理和操作。其實郵件操作大多大同小異,這次只是希望介紹一下ABP中實現功能的程式碼結構而已,以下是具體過程

演示的ABP程式碼版本為0.9.0.0,不過後面版本對於這部分的修改較少,所以完全不影響之後版本的移植使用

2. 實現過程

ABP的Mail操作放在了Abp.Net.Mail和Abp.Net.Mail.Smtp中,第一步先讓我們直接看看這個資料夾下類及介面的程式碼圖(未經允許不可使用)

1. 程式碼圖(重)

根據程式碼圖可以發現ABP對於Mail處理主要由三部分組成

  • 第一部分是通過繼承SettingProvider的EmailSettingProvider來對Mail相關引數進行設定(其中EmailSettingNames定義相關字串)
  • 第二部分是以IEmailSenderConfiguration介面為基派生出的對SettingProvider設定的郵件引數進行讀取和傳輸的相關操作類
  • 第三部分是以IEmailSender介面為基派生出的Mail傳送操作相關類

至於Smtp開頭的檔案,則是以Smtp形式進行郵件傳送的一種實現檔案而已,後文也將直接使用該種方式進行處理

2.具體實現

在具體的實現上,我發現ABP本身的Mail相關類已經十分完整,只是在郵件引數的配置上需要採取自定義的實現,所以我直接抽取了ABP的原始碼來進行演示

2.1 定義AppSettingNames及AppSettingProvider

AppSettingNames中定義相關的唯一字串,大家可以認為是Key,而AppSettingProvider中則是將Key對應的郵件引數賦值,供之後的Configuration讀取

郵件功能推薦放在Core模組中,完成相關的provider後在CoreModule加入Configuration.Settings.Providers.Add<AppSettingProvider>();

即可生效

public static class AppSettings
{
    /// <summary>
    /// SMTP related email settings.
    /// </summary>
    public static class Smtp
    {
        /// <summary>
        /// Abp.Net.Mail.DefaultFromAddress
        /// </summary>
        public const string DefaultAddress = "Trucking.Net.Mail.DefaultFromAddress";

        /// <summary>
        /// Abp.Net.Mail.DefaultFromDisplayName
        /// </summary>
        public const string DefaultDisplayName = "Trucking.Net.Mail.DefaultFromDisplayName";

        /// <summary>
        /// Abp.Net.Mail.Smtp.Host
        /// </summary>
        public const string Host = "Trucking.Net.Mail.Smtp.Host";

        /// <summary>
        /// Abp.Net.Mail.Smtp.Port
        /// </summary>
        public const string Port = "Trucking.Net.Mail.Smtp.Port";

        /// <summary>
        /// Abp.Net.Mail.Smtp.UserName
        /// </summary>
        public const string UserName = "Trucking.Net.Mail.Smtp.UserName";

        /// <summary>
        /// Abp.Net.Mail.Smtp.Password
        /// </summary>
        public const string Password = "Trucking.Net.Mail.Smtp.Password";

        /// <summary>
        /// Abp.Net.Mail.Smtp.Domain
        /// </summary>
        public const string Domain = "Trucking.Net.Mail.Smtp.Domain";

        /// <summary>
        /// Abp.Net.Mail.Smtp.EnableSsl
        /// </summary>
        public const string EnableSsl = "Trucking.Net.Mail.Smtp.EnableSsl";

        /// <summary>
        /// Abp.Net.Mail.Smtp.UseDefaultCredentials
        /// </summary>
        public const string UseDefaultCredentials = "Trucking.Net.Mail.Smtp.UseDefaultCredentials";
    }
}

public class AppSettingProvider : SettingProvider
{
    public override IEnumerable<SettingDefinition> GetSettingDefinitions(SettingDefinitionProviderContext context)
    {
        return new[]
        {
            new SettingDefinition(AppSettings.Smtp.Host, "smtp.gmail.com", L("SmtpHost"),
                scopes: SettingScopes.Application | SettingScopes.Tenant),
            new SettingDefinition(AppSettings.Smtp.Port, "587", L("SmtpPort"),
                scopes: SettingScopes.Application | SettingScopes.Tenant),
            new SettingDefinition(AppSettings.Smtp.UserName, "[email protected]", L("Username"),
                scopes: SettingScopes.Application | SettingScopes.Tenant),
            new SettingDefinition(AppSettings.Smtp.Password, "mypassword", L("Password"),
                scopes: SettingScopes.Application | SettingScopes.Tenant),
            new SettingDefinition(AppSettings.Smtp.Domain, "", L("DomainName"),
                scopes: SettingScopes.Application | SettingScopes.Tenant),
            new SettingDefinition(AppSettings.Smtp.EnableSsl, "true", L("UseSSL"),
                scopes: SettingScopes.Application | SettingScopes.Tenant),
            new SettingDefinition(AppSettings.Smtp.UseDefaultCredentials, "false", L("UseDefaultCredentials"),
                scopes: SettingScopes.Application | SettingScopes.Tenant),
            new SettingDefinition(AppSettings.Smtp.DefaultAddress, "[email protected]",
                L("DefaultEmailAddress"), scopes: SettingScopes.Application | SettingScopes.Tenant),
            new SettingDefinition(AppSettings.Smtp.DefaultDisplayName, "CompanyName",
                L("DefaultDisplayName"), scopes: SettingScopes.Application | SettingScopes.Tenant)
        };
    }

    private static LocalizableString L(string name)
    {
        return new LocalizableString(name, AbpConsts.LocalizationSourceName);
    }
}

2.2 EmailSenderConfiguration配置

這個類的作用如上面提到的那樣,主要是讀取自定義的AppSettingProvider中設定的郵件引數值

IUserEmailSenderConfiguration介面略

public class UserEmailSenderConfiguration : TruckingServiceBase, IUserEmailSenderConfiguration, ITransientDependency
{
    /// <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.GetSettingValue(name);
        if (value.IsNullOrEmpty())
        {
            throw new AbpException(String.Format("Setting value for '{0}' is null or empty!", name));
        }

        return value;
    }

    /// <summary>
    /// SMTP Host name/IP.
    /// </summary>
    public string Host
    {
        get { return GetNotEmptySettingValue(AppSettings.Smtp.Host); }
    }

    /// <summary>
    /// SMTP Port.
    /// </summary>
    public int Port
    {
        get { return SettingManager.GetSettingValue<int>(AppSettings.Smtp.Port); }
    }

    /// <summary>
    /// User name to login to SMTP server.
    /// </summary>
    public string UserName
    {
        get { return GetNotEmptySettingValue(AppSettings.Smtp.UserName); }
    }

    /// <summary>
    /// Password to login to SMTP server.
    /// </summary>
    public string Password
    {
        get { return GetNotEmptySettingValue(AppSettings.Smtp.Password); }
    }

    /// <summary>
    /// Domain name to login to SMTP server.
    /// </summary>
    public string Domain
    {
        get { return SettingManager.GetSettingValue(AppSettings.Smtp.Domain); }
    }

    /// <summary>
    /// Is SSL enabled?
    /// </summary>
    public bool EnableSsl
    {
        get { return SettingManager.GetSettingValue<bool>(AppSettings.Smtp.EnableSsl); }
    }

    /// <summary>
    /// Use default credentials?
    /// </summary>
    public bool UseDefaultCredentials
    {
        get { return SettingManager.GetSettingValue<bool>(AppSettings.Smtp.UseDefaultCredentials); }
    }

    public string DefaultAddress
    {
        get { return GetNotEmptySettingValue(AppSettings.Smtp.DefaultAddress); }
    }

    public string DefaultDisplayName
    {
        get { return SettingManager.GetSettingValue(AppSettings.Smtp.DefaultDisplayName); }
    }
}

2.3 SmtpEmailSender實現(Smtp實現郵件傳送)

UserSmtpEmailSender類才是真正的對Mail操作類,它通過注入IUserEmailSenderConfiguration介面,讀取相關的Mail引數,如Host,UserName,Password等,然後再呼叫.NET的Mail傳送郵件。

IUserSmtpEmailSender介面略

public class UserSmtpEmailSender : IUserSmtpEmailSender, ITransientDependency
{
    private readonly IUserEmailSenderConfiguration _configuration;

    public UserSmtpEmailSender(IUserEmailSenderConfiguration configuration)
    {
        _configuration = configuration;
    }
    
    public async Task SendAsync(string to, string subject, string body, bool isBodyHtml = true)
    {
        await SendAsync(_configuration.DefaultAddress, to, subject, body, isBodyHtml);
    }

    public void Send(string to, string subject, string body, bool isBodyHtml = true)
    {
        Send(_configuration.DefaultAddress, to, subject, body, isBodyHtml);
    }

    public 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 void Send(string from, string to, string subject, string body, bool isBodyHtml = true)
    {
        Send(new MailMessage(from, to, subject, body) {IsBodyHtml = isBodyHtml});
    }

    public async Task SendAsync(MailMessage mail, bool normalize = true)
    {
        if (normalize)
            NormalizeMail(mail);

        await SendEmailAsync(mail);
    }

    public void Send(MailMessage mail, bool normalize = true)
    {
        if (normalize)
            NormalizeMail(mail);

        SendEmail(mail);
    }

    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;
        }
    }

    /// <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.DefaultAddress,
                _configuration.DefaultDisplayName,
                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;
    }

    protected async Task SendEmailAsync(MailMessage mail)
    {
        using (var smtpClient = BuildClient())
        {
            await smtpClient.SendMailAsync(mail);
        }
    }

    protected void SendEmail(MailMessage mail)
    {
        using (var smtpClient = BuildClient())
        {
            smtpClient.Send(mail);
        }
    }
}

之後我們只需要再呼叫該EmailSender的SendAsync,填入對應的引數,親測有效。如果之後要更換郵件元件,則只需要實現對應的UserLibraryEmailSerder即可。

至此,我們便將ABP中單獨的一個郵件功能抽離了出來並做了相關解釋,其實只要花點功夫,自己手動剝離程式碼圖也可以理解了。至於一個簡單的郵件功能為什麼在ABP中要實現得如此複雜,每個程式設計師有每個程式設計師的答案,還是繼續學習吧

相關推薦

結合ABP原始碼實現郵件傳送功能

1. 前言 最近pm臨時提出了多種郵件驗證操作的需求,因為一時間也沒有找到好的郵件收發元件,也抱著研究ABP的心態,就花了幾小時時間探究了一下ABP中關於Email的處理和操作。其實郵件操作大多大同小異,這次只是希望介紹一下ABP中實現功能的程式碼結構而已,以下是具體過程 演示的ABP程式碼版本為

JAVA在不基於XML配置檔案的情況下實現郵件傳送功能(郵箱轟炸)

    今天要講的是如何用Java程式碼實現簡單郵件傳送和複雜郵件傳送的功能,這裡我使用的是QQ郵箱,你們也可以嘗試使用其他的郵箱哦~ 想實現郵件傳送功能首先郵箱賬號必須要開啟 SMTP 服務,在網頁登入郵箱後點擊設定→賬戶然後下拉,如圖 &nb

使用java實現郵件傳送功能(已封裝)

現如今,用郵件傳送訊息的人越來越少,可是並不影響我們學習java。 以下給大家帶來自己寫的封裝類,可以直接使用。 首先,需要jar包: 普通javaweb專案:mail.jar maven管理專案:  <dependency>     &

SpringBoot快速實現郵件傳送功能-百測百靈

2018年11月10日星期六 隨筆 筆記 springboot整合郵件傳送 一、匯入依賴包 org.springframework.boot spring-boot-starter-mail 二、開啟服務(一個即可) 三、傳送簡訊:配置郵件客戶端到1069

JavaMail實現郵件傳送功能

最近的專案要使用javamail進行郵件傳送,寫這篇部落格總結下 傳送簡單的郵件 在進行郵件傳送之前要引入javamail的Maven依賴 dependency> <groupId>javamail</groupId> &l

Python 實現郵件傳送功能(初級)

  在我們日常專案中,會經常使用到郵件的傳送功能,如何利用Python傳送郵件也是一項必備的技能。本文主要講述利用Python來發送郵件的一些基本操作。   本章主要包含知識點: 郵件傳送原理簡述即常用smtp郵箱伺服器 傳送文字郵件 傳送html郵件   我們一般傳送郵件時,用到的代理有outlook,

Python 實現郵件傳送功能(進階)

上篇文章已經介紹了利用Python傳送文字訊息的用法,也在文末遺留了如何傳送圖片和附件的問題,本章主要來回答這兩個問題。   本章主要包含知識點: 1. 如何將圖片放到郵件主體中傳送 2. 如何傳送附件 問題一: 如何將圖片放在郵件主體中傳送 從上篇中應該都已知道,其實發送郵件,就是傳送Html格式

spring-boot-route(二十二)實現郵件傳送功能

在專案開發中,除了需要簡訊驗證外,有時候為了節省 簡訊費也會使用郵件傳送。在Spring專案中傳送郵件需要封裝複雜的訊息體,不太方便。而在Spring Boot專案中傳送郵件就太簡單了,下面一起來看看Spring Boot如何傳送郵件。 本文以126郵箱為例進行郵件傳送功能,其他郵箱的配置也都大同小異。

利用EasySQLMAIL實現自動資料提取和郵件傳送功能 (1)

轉自:http://blog.sina.com.cn/s/blog_1549483b70102wioy.html 最近幾個月每天都在發通報。過程很繁瑣,動作很機械,整個人就是一部機器,執行SQL,填Excel,發郵件。所以想把日報自動化了。最後找到一個叫EasySQLMAIL的軟體,試了一下,很簡單也很方便

.NET開發郵件傳送功能的全面教程(含郵件元件原始碼)

今天,給大家分享的是如何在.NET平臺中開發“郵件傳送”功能。在網上搜的到的各種資料一般都介紹的比較簡單,那今天我想比較細的整理介紹下: 1)郵件基礎理論知識 2)郵件傳送相關.NET類庫 3)介紹我開發的一個傳送郵件的小元件(MailHelper) 4)MailHelper元件的一個示例以及幾種

C#實現郵件傳送功能

1.實現原理: 微軟封裝好的MailMessage類:主要處理髮送郵件的內容(如:收發人地址、標題、主體、圖片等等) 微軟封裝好的SmtpClient類:主要處理用smtp方式傳送此郵件的配置資訊(如:郵件伺服器、傳送埠號、驗證方式等等) SmtpClient主要進行了三層的封裝:Socket

VC MFC 郵件傳送功能實現

http://www.naughter.com/smtp.html CPJNSMTP目前是寫的比較完善的MFC程式,目前它原始碼最新是支援VS2015。 這個庫支援多國語言,傳送郵件不會出現亂碼。 並且支援SSL驗證,筆者已在QQ和163郵箱測通過,注意QQ郵箱設定第三方收

實現簡單的郵件傳送功能

1 建立路由 Route::get('/',function()){ //查詢Id為1的使用者 $user=\App\User::find(1); //to方法後面接的是郵件地址;send()方法接受的是預設實體類,該類可以通過p

Java實現郵件傳送(傳統方式)

package jl.bh.shy.utils; import java.util.Properties; import javax.mail.Address; import javax.mail.Session; import javax.mail.Transport; impor

Log4j2配置SMTP郵件實現郵件傳送

大綱: 官網配置資訊 實際使用 一、官網配置資訊 官網SMTPAppender配置 <?xml version="1.0" encoding="UTF-8"?> <Configuration status="

JavaMail實踐--實現郵件傳送

一、介紹   1、主要功能:     實現普通郵件的傳送     實現帶有HTML標籤的內容傳送     實現帶有附件的郵件傳送   2、API JavaMail mail.jar 1.4.5 JAF(版本 1.1.1) activation.jar   3、QQ郵箱的認證   

SpringBoot實現郵件傳送及其工具類封裝

SpringBoot郵件傳送工具類 環境:JDK8、IDEA 依賴:SpringBoot-1.5.10、spring-boot-starter-mail、spring-boot-starter-thymeleaf、spring-boot-start

McAfee阻止郵件傳送功能

自己寫的郵件傳送功能,在本地機器上可以傳送,但是放到伺服器上面之後就不能傳送了,捕獲到的異常是“以一個訪問許可權不允許的方式做了一個訪問套接字的嘗試”,找了很久,終於發現是被McAfee給阻止了,下面是解決辦法: 1、滑鼠右鍵單擊螢幕右下角McAfee圖示 2、單擊“VirusScan控制檯“ 3、在彈

Java實現郵件傳送(很簡單)

Java實現郵件傳送,需要指定郵件伺服器,和自己的郵箱賬號和密碼,謹記 自己的郵箱必須得到到客戶端授權碼,尤其是新開的郵箱,具體看程式碼,包括附件傳送 public class EmailUtils { private static String from = ""; //郵箱賬號 p

使用JavaMail實現郵件傳送

電子郵件協議 電子郵件在網路中傳輸和網頁一樣需要遵從特定的協議,常用的電子郵件協議包括 SMTP,POP3,IMAP。其中郵件的建立和傳送只需要用到 SMTP協議,所以本文也只會涉及到SMTP協議。SMTP 是 Simple Mail Transfer Protocol