最近准备给网站接入邮件通知功能,用的是阿里云的企业邮箱,本以为很快就能实现,但是最终花了将近两天的时间,遇到了各种坑和雷,特此记录,希望能帮助到有需要的朋友。
一、邮件发送的各种端口:
25端口:为SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)服务所开放的,是用于发送邮件,邮件内容不加密,安全性低;
465端口:为SMTPS(SMTP-over-SSL)协议服务开放的,这是SMTP协议基于SSL安全协议之上的一种变种协议,它继承了SSL安全协议的非对称加密的高度安全可靠性,可防止邮件泄露。SMTPS和SMTP协议一样,也是用来发送邮件的,只是更安全些,防止邮件被黑客截取泄露,还可实现邮件发送者抗抵赖功能。防止发送者发送之后删除已发邮件,拒不承认发送过这样一份邮件;
587端口:是STARTTLS协议的 属于TLS通讯协议 只是他是在STARTTLS命令执行后才对之后的原文进行保护的;
二、阿里云企业邮箱及国内云服务器对25、465、587端口的支持:
25端口:国内云服务器默认封禁,以阿里云服务器为例,如果你想开通,须要额外申请,解封参照帮助文档(https://help.aliyun.com/document_detail/56130.html);
587端口:国内云服务可telnet smtp.qiye.aliyun.com 587通,但是国外及香港云服务器怎么都telnet不通;不知被哪里限制了实在不能理解,刚好我这用到了香港云服务器,被坑了一把;

465端口:国内、国外、香港云服务器都可以telnet smtp.qiye.aliyun.com 465通。
综上避坑点1:25要申请解封,申请了还不一定能给你解封;587香港和国外服务器连接不通;最好用465端口;
三、465端口的雷和坑
一开始使用.net的System.Net.Mail来发送邮件,也选用的是465端口,EnableSsl设置为true,但是结果却是死活连不上服务器发送不了,最后一查发现System.Net.Mail不支持?你说坑不坑,.net自己的发邮件的库居然不支持?
原因为:NET Framework的System.Net.Mail组件默认不支持Implicit SSL,而465端口通常使用Implicit SSL进行加密。因此,直接使用.NET Framework发送邮件时,可能会遇到不支持465端口的问题。阿里云企业邮箱推荐使用465端口进行加密传输。然而.NET Framework的SmtpClient类不支持Implicit SSL,导致无法通过465端口发送邮件。
而.net官方还建议大家考虑使用如MailKit、MimeKit等第三方库代System.Net.Mail来发邮件,真的无语。
最后没办法,我既不想云申请25端口解封和客服扯皮,提交了工单让他们处理香港服务器587端口不通的问题也半天没回复,只能用465端口,最后只能换成用MailKit来发了。
四、发送邮件时的验证密码并不是邮箱密码
发送邮件时验证密码不是邮箱密码,这个事我是知道的,因为以前用QQ邮箱等有经验,不过最终还是被坑了一把,真的是要吐槽一把阿里云企业邮箱的这个交互功能。验证密码申请的方式如下:
1、使用账号密码登录阿里云企业邮箱后台:https://qiye.aliyun.com;
2、进入设置->账户安全 找到三方客户端安全密码; 
3、点击生成新密码,输入账号密码后他就给你弹出了个新密码,还让你复制,如果你直接复制关闭窗口就懵逼了,那个密码复制出来根本没用,因为他这里还要你输个设置名再保存后才是真正的有效密码。我就在这被坑了一次。

最后分享一个发送邮件的帮助类:
using MailKit.Security;
using MimeKit;
using System.Net;
using MailKit.Net.Smtp;
using System.Net.Mail;
namespace CBC.Utility
{
public class EmailHelper
{
/// <summary>
/// 是否初始化
/// </summary>
private bool isInit=false;
/// <summary>
/// 邮箱对象
/// </summary>
private static EmailHelper self {get; set;}
/// <summary>
/// smtp
/// </summary>
private string smtp { get; set; }
/// <summary>
/// email
/// </summary>
private string email { get; set; }
/// <summary>
/// password
/// </summary>
private string password { get; set; }
/// <summary>
/// senderName
/// </summary>
private string senderName { get; set; }
/// <summary>
/// port
/// </summary>
private int port { get; set; }
private EmailHelper()
{
smtp = "";
email = "";
password = "";
senderName = "";
port = 25;
}
/// <summary>
/// 构造函数
/// </summary>
static EmailHelper()
{
self=new EmailHelper();
}
/// <summary>
/// 初始华函数
/// </summary>
/// <param name="smtp"></param>
/// <param name="email"></param>
/// <param name="password"></param>
/// <param name="senderName"></param>
/// <param name="port"></param>
public static void Init(string smtp, string email, string password, string senderName,int port)
{
self.isInit = true;
if (!string.IsNullOrEmpty(smtp) && !string.IsNullOrEmpty(email) && !string.IsNullOrEmpty(password) && !string.IsNullOrEmpty(senderName))
{
self.smtp = smtp;
self.email = email;
self.password = password;
self.senderName = senderName;
self.port = port;
}
}
#region 发送邮件
/// <summary>
/// 简单发送邮件功能(支持25、587端口)
/// </summary>
/// <param name="title">标题</param>
/// <param name="content">内容</param>
/// <param name="toEmail">收件人</param>
/// <returns></returns>
public static Result<bool> SendMail(string title, string content,string toEmail)
{
Result<bool> ret = new Result<bool>();
if (self.isInit)
{
if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(content))
{
ret.Obj = false;
ret.Msg = "参数错误!";
}
try
{
System.Net.Mail.SmtpClient client = new System.Net.Mail.SmtpClient();
client.Host = self.smtp;
client.UseDefaultCredentials = false;
client.Credentials = new System.Net.NetworkCredential(self.email, self.password);
//星号改成自己邮箱的密码
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.EnableSsl = true;
client.Port=self.port;
System.Net.Mail.MailMessage message = new MailMessage();
//填充发送者邮箱
string from = self.email;
MailAddress ad_from = new MailAddress(from, self.senderName);//发送人
message.From = ad_from;
message.To.Add(toEmail);
message.Subject = title;
message.Body = content;
message.BodyEncoding = System.Text.Encoding.UTF8;
message.IsBodyHtml = true;
client.Send(message);
ret.Obj = true;
ret.Msg = "发送成功!";
return ret;
}
catch (Exception ex)
{
ret.Obj = false;
ret.Msg = "发送失败!" + ex.Message;
}
}
else
{
ret.Obj = false;
ret.Msg = "发送失败!请先初始化发件邮箱配置";
}
return ret;
}
/// <summary>
/// MailKit 发送邮件功能 支持25、587、465端口
/// </summary>
/// <param name="title"></param>
/// <param name="content"></param>
/// <param name="toEmail"></param>
/// <returns></returns>
public static Result<bool> SendMailKit(string title, string content, string toEmail)
{
Result<bool> ret = new Result<bool>();
if (self.isInit)
{
if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(content))
{
ret.Obj = false;
ret.Msg = "参数错误!";
return ret;
}
MimeMessage message = new MimeMessage();
message.From.Add(new MailboxAddress(self.senderName, self.email));
message.To.Add(new MailboxAddress(toEmail, toEmail));
message.Subject = title;
BodyBuilder bodyBuilder = new BodyBuilder
{
HtmlBody = content
};
message.Body = bodyBuilder.ToMessageBody();
using (var client = new MailKit.Net.Smtp.SmtpClient())
{
try
{
client.Connect(self.smtp, self.port, SecureSocketOptions.Auto);
client.Authenticate(self.email, self.password);
string result = client.Send(message);
ret.Obj = true;
ret.Msg = "发送成功!";
}
catch (Exception ex)
{
ret.Obj = false;
ret.Msg = "发送失败!" + ex.Message;
}
finally
{
client.Disconnect(true);
}
}
return ret;
}
else
{
ret.Obj = false;
ret.Msg = "发送失败!请先初始化发件邮箱配置";
}
return ret;
}
#endregion
}
}用法:
1、在配置文件中加入以下配置
"Smtp": "smtp.qiye.aliyun.com",
"SmtpPort": 465,
"Email": "邮箱地址",
"EmailPassword": "邮箱密码",
"SenderName": "发件人"
2、使用前调用init方法初始化邮件信息,.net core 可以放在Program.cs当中:
//初始化邮件配置
string smtp= builder.Configuration.GetValue<string>("appSettings:Smtp");
string email= builder.Configuration.GetValue<string>("appSettings:Email");
string password= builder.Configuration.GetValue<string>("appSettings:EmailPassword");
string senderName = builder.Configuration.GetValue<string>("appSettings:SenderName");
int smtpPort = builder.Configuration.GetValue<int>("appSettings:SmtpPort");
EmailHelper.Init(smtp, email, password, senderName, smtpPort);3、最后在发送邮件的地方调用EmailHelper.SendMailKit(string title, string content,string toEmail)方法。
点赞(3)