iT邦幫忙

2022 iThome 鐵人賽

DAY 27
0
Modern Web

.NET教我做人系列 第 27

Day27 如何發送電子郵件

  • 分享至 

  • xImage
  •  

大家好啊,今天的鐵人賽要來介紹我們如何在ASP.NET Core 發送電子郵件。我們的應用程序將以純文本的形式來發送郵件,也支持附件的功能,我們還會知道如何用HTML的模板來發送郵件,這次的功能我們要先去使用MailKit 的第三方套件

SMTP

當我們要發送郵件,我們需要一個服務器。現在設置自己的服務器/應用程序來做到這一點是不切實際的。因此,我們使用其他提供商的服務器。最受歡迎的當然是 Gmail。在我們的例子中,主機是指 SMTP 服務器

SMTP: SMTP 或簡單郵件傳輸協議服務器主要目的是發送和接收郵件的應用程序。當您發送電子郵件時,SMTP 服務器會確定目標域並將郵件中繼到相應的服務器

SMTP需要內容

  1. Gmail ID (建議不要使用個人電子郵件的ID)
  2. 密碼(應用程式密碼)
  3. 主機或SMTP服務器地址(Gmail, smtp.gmail.com)
  4. 端口(Port),465(SSL)或587(TLS)

這裡如何啟用安全驗證跟應用程式密碼我就不多說,起參考下面連結
https://shinher.gitbook.io/shinher/ru-he-shen-qing-ying-yong-cheng-shi-zhuan-yong-mi-ma

實際操作

模組新增

接著我們去新增兩個模型,一個要來放我們要發送的信箱、主題、正文與附件等參數,另一個釋放寄件人的模型

請求模組

public class MailRequest
{
    public string ToEmail { get; set; }
    public string Subject { get; set; }
    public string Body { get; set; }
    public List<IFormFile> Attachments { get; set; }
}

寄件人模組

public class MailSettings
{
    public string Mail { get; set; }
    public string DisplayName { get; set; }
    public string Password { get; set; }
    public string Host { get; set; }
    public int Port { get; set; }
}

這兩個模組我是把他們放在Models/MailSetting.cs 裡

MailSetting 使用

接著我們到appsettings.json 裡先去設定我們寄件人的設定

"MailSettings": {
  "Mail": "<fromemail>",
  "DisplayName": "<displayname>",
  "Password": "<yourpasswordhere>",
  "Host": "smtp.gmail.com",
  "Port": 587
}

像之前我們要取appsetting.json 的資料時都去要builder.Configuration.GetConnectionString()這樣一個一個去拿,這樣的方式很麻煩也很佔空間,所以在這裡我們有另一種方式更好去拿MailSettings 內的值

先去註冊組態注入服務

builder.Services.Configure<MailSettings>(builder.Configuration.GetSection("MailSettings"));

這裡GetSection 方法可根據 key 取得某區塊的組態物件,並回傳一個代表組態區塊的 IConfigurationSection,而 Configure<T> 則需要給定一個代表組態資訊的 IConfiguration,由於 IConfigurationSection 實作了 IConfiguration 介面,所以這邊我們可以直接將 GetSection 的結果作為參數傳入

再來我們可以使用IOptions<T>的方式進行注入

mail的interface

先去創個interface來當發郵寄的功能,Helper/IMailService.cs

public interface IMailService
{
    Task SendEmailiAsync(MailRequest mailRequest);
}

mail實際功能

接著就是功能的部分,Helper/MailService.cs
記得要去繼承剛才的IMailService

public class MailService : IMailService
    {
        // ... 
    }

在建構函數時就會先把appsetting.json 裡的值抓近來,透過參數IOptions<MailSettings>來把剛才註冊的Configure裡提供的Value來把對應的key 放入

private readonly MailSettings _mailSettings;
public MailService(IOptions<MailSettings> mailSettings)
{
    _mailSettings = mailSettings.Value;
}

實際跑程式後可以看到appsetting.json 的值真的有被套用近來

最後就剩功能的地方,在這裡我把它分成三的部分

  1. 寄/發送人資訊、主題
  2. 發送內容
  3. smtp的寄送方式
public async Task SendEmailiAsync(MailRequest mailRequest)
{
    // 寄/發送人的資訊
    var email = new MimeMessage();
    email.Sender = MailboxAddress.Parse(_mailSettings.Mail);
    email.To.Add(MailboxAddress.Parse(mailRequest.ToEmail));
    email.Subject = mailRequest.Subject; // 主題
    //=============================================================
    //發送內容
    var builder = new BodyBuilder();
    if(mailRequest.Attachments != null) // 事處理檔案的部分
    {
        byte[] fileBytes;
        foreach (var file in mailRequest.Attachments)
        {
            if (file.Length > 0)
            {
                using (var ms = new MemoryStream())
                {
                    file.CopyTo(ms);
                    fileBytes = ms.ToArray();
                }
                builder.Attachments.Add(file.FileName, fileBytes, ContentType.Parse(file.ContentType));
            }
        }
    }
    builder.HtmlBody = mailRequest.Body; // 郵件訊息內容
    email.Body = builder.ToMessageBody();
    //=============================================================
    //smtp的寄送方式(使用appsetting.json的資訊)
    using var smtp = new SmtpClient();
    smtp.Connect(_mailSettings.Host, _mailSettings.Port, SecureSocketOptions.StartTls);
    smtp.Authenticate(_mailSettings.Mail, _mailSettings.Password);
    await smtp.SendAsync(email);
    smtp.Disconnect(true);
}

API使用

接著我們就去套用剛才寫好的功能

[Route("api/[controller]")]
[ApiController]
public class MailController : ControllerBase
{
    // 套用Mail的Method
    private readonly IMailService _mailService;
    public MailController(IMailService mailService)
    {
        _mailService = mailService;
    }
    [HttpPost("send")]
    public async Task<IActionResult> SendMail([FromForm]MailRequest request)// 這裡因為有檔案所以要使用`[FromForm]`
    {
        try
        {
            await _mailService.SendEmailiAsync(request);
            return Ok();
        }
        catch(Exception)
        {
            throw;
        }
    }
}

特別注意,記得要去註冊剛剛的功能,不然你會一直報錯

builder.Services.AddSingleton<IMailService, MailService>();

最後去跑你要寄的email應該就行了

今天的鐵人賽就先到這裡啦,還剩三天再撐過就可以輕鬆了,希望大家會喜歡今天的主題~~~

參考資料:


上一篇
Day26 CORS(跨來源資源共用)
下一篇
Day28 Log 記錄管理
系列文
.NET教我做人30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言