在很多應用系統中,都會有郵件發送功能。例如當用戶注冊過程中向用戶郵箱發送驗證信息;當客戶完成訂單時發送郵件進行提醒;當系統出現異常時向指定賬號發送郵件報警等等。
以前,開發過程中大多數都是使用微軟的smtpclient發送郵件。但是微軟本身封裝的組件stmpclient內部連接管理混亂(可查看https://www.infoq.cn/article/2017/04/MailKit-MimeKit-Official);並且支持的協議不足,特別是ssl方面,現在已經被微軟標記為obsolete(過時的)。曾經在使用阿里雲作為服務器需要發郵件時,阿里雲提示禁用25端口(25端口不安全,容易被黑)而推薦使用465端口。但是微軟的StmpClient竟然不支持465...着實坑了一把。
現今在實現郵件發送功能時,更多的是選擇使用(微軟也推薦的)第三方組件Mailkit。當然我們也可以使用一些雲郵箱服務,例如Amazon Simple Email Service。
MailKit簡單實現郵件發送
MailKit是開源的,基於MimeKit的跨平台.NET郵件庫,支持IMAP、POP3、SMTP協議。也是當前微軟推薦使用的。
開源地址:https://github.com/jstedfast/MailKit
以下是簡單實現郵件發送功能
1 public class MailKitManagement 2 { 3 public readonly MailKitConfig _mailKitConfig; 4 public MailKitManagement(IOptions<MailKitConfig> mailKitConfigOption) 5 { 6 _mailKitConfig = mailKitConfigOption?.Value; 7 } 8 /// <summary> 9 /// send email 10 /// </summary> 11 /// <param name="toMailAddressList"></param> 12 /// <param name="ccAddresList"></param> 13 /// <param name="subject"></param> 14 /// <param name="body"></param> 15 /// <param name="attachmentList"></param> 16 /// <param name="isHtml"></param> 17 /// <returns></returns> 18 public async Task SendMessageAsync(List<string> toMailAddressList, List<string> ccAddresList, string subject, string body, List<string> attachmentList = null, bool isHtml = false) 19 { 20 var mailMessage = new MimeMessage(); 21 mailMessage.From.Add(new MailboxAddress(_mailKitConfig.DisplayName, _mailKitConfig.MailAddress)); 22 foreach (var mailAddressItem in toMailAddressList) 23 { 24 mailMessage.To.Add(MailboxAddress.Parse(mailAddressItem)); 25 } 26 if (ccAddresList != null) 27 { 28 ccAddresList.ForEach(p => 29 { 30 mailMessage.Cc.Add(MailboxAddress.Parse(p)); 31 }); 32 } 33 34 mailMessage.Subject = subject; 35 TextPart messageBody = null; 36 if (isHtml) 37 { 38 messageBody = new TextPart(TextFormat.Html) 39 { 40 Text = body, 41 }; 42 } 43 else 44 { 45 messageBody = new TextPart(TextFormat.Plain) 46 { 47 Text = body, 48 }; 49 } 50 var mulitiPart = new Multipart("mixed") 51 { 52 }; 53 mulitiPart.Add(messageBody); 54 if (attachmentList != null && attachmentList.Count > 0) 55 { 56 foreach (var attatchItem in attachmentList) 57 { 58 using (var stream = File.OpenRead(attatchItem)) 59 { 60 var attachment = new MimePart() 61 { 62 Content = new MimeContent(stream, ContentEncoding.Default), 63 ContentDisposition = new ContentDisposition(ContentDisposition.Attachment), 64 ContentTransferEncoding = ContentEncoding.Base64, 65 FileName = Path.GetFileName(attatchItem) 66 }; 67 mulitiPart.Add(attachment); 68 } 69 } 70 } 71 mailMessage.Body = mulitiPart; 72 using (var client = new MailKit.Net.Smtp.SmtpClient()) 73 { 74 if (_mailKitConfig.IsSsl) 75 { 76 client.ServerCertificateValidationCallback = (s, c, h, e) => true; 77 } 78 79 client.Connect(_mailKitConfig.MailServer, _mailKitConfig.SmtpPort, false); 80 81 // Disable the XOAUTH2 authentication mechanism. 82 //client.AuthenticationMechanisms.Remove("XOAUTH2"); 83 84 // Note: only needed if the SMTP server requires authentication 85 client.Authenticate(_mailKitConfig.MailAddress, _mailKitConfig.Password); 86 await client.SendAsync(mailMessage); 87 client.Disconnect(true); 88 } 89 } 90 }
Amazon Simple Email Service簡單實現發送郵件
Amazon Simple Email Service 是Amazon提供的郵件服務。需要有響應的Amazon賬號,而且在達到一定量時會被要求收費,一般不建議個人使用。對於一些企業可以考慮(但也很少會用)。(之前工作中跟老外部分有交互時,老外推薦使用....)
1 /* 2 * Amazon Simple Email Service 3 * 參照 https://docs.aws.amazon.com/ses/latest/DeveloperGuide/send-using-sdk-net.html 4 * 5 */ 6 /// <summary> 7 /// aws email helper 8 /// need to using AWSSDK.Core.3.7.0.44 and AWSSDK.SimpleEmail.3.7.0.42. 9 /// </summary> 10 public class AwsEmailManagement 11 { 12 13 private readonly AwsEmailConfig _awsConfig; 14 public AwsEmailManagement(IOptions<AwsEmailConfig> awsConfigOption) 15 { 16 this._awsConfig = awsConfigOption?.Value; 17 } 18 19 /// <summary> 20 /// send email 21 /// </summary> 22 /// <param name="toEmailList"></param> 23 /// <param name="ccEmailList"></param> 24 /// <param name="subject"></param> 25 /// <param name="body"></param> 26 /// <param name="isHtml"></param> 27 /// <returns></returns> 28 public async Task SendMessageAsync(List<string> toMailAddressList, List<string> ccAddresList, string subject, string body, bool isHtml = false,string configurationSetName = "") 29 { 30 31 AWSCredentials awsCredentials = new BasicAWSCredentials(_awsConfig.AccessKey, _awsConfig.SecretKey); 32 AmazonSimpleEmailServiceConfig clientConfiguration = new AmazonSimpleEmailServiceConfig(); 33 if (_awsConfig.IsEnableProxy) 34 { 35 clientConfiguration.ProxyHost = _awsConfig.ProxyUrl; 36 clientConfiguration.ProxyPort = _awsConfig.ProxyPort; 37 } 38 using (var client = new AmazonSimpleEmailServiceClient(awsCredentials, clientConfiguration)) 39 { 40 var sendRequest = new SendEmailRequest 41 { 42 Source = _awsConfig.EmailAddress, 43 Destination = new Destination 44 { 45 ToAddresses = toMailAddressList, 46 }, 47 Message = new Message 48 { 49 Subject = new Content(subject), 50 Body = new Body(), 51 }, 52 53 }; 54 55 if (isHtml) 56 { 57 sendRequest.Message.Body.Html = new Content(body); 58 } 59 else 60 { 61 sendRequest.Message.Body.Text = new Content(body); 62 } 63 if (ccAddresList != null && ccAddresList.Count > 0) 64 { 65 sendRequest.Destination.CcAddresses = ccAddresList; 66 } 67 68 sendRequest.ConfigurationSetName =configurationSetName; 69 70 var response = await client.SendEmailAsync(sendRequest); 71 } 72 } 73 }
配置文件類(AwsEmailConfig)定義
1 public class AwsEmailConfig 2 { 3 public string AccessKey { get; set; } 4 public string SecretKey { get; set; } 5 public bool IsEnableProxy { get; set; } 6 public string ProxyUrl { get; set; } 7 public int ProxyPort { get; set; } 8 9 public string EmailAddress { get; set; } 10 11 }