最近准备给网站接入邮件通知功能,用的是阿里云的企业邮箱,本以为很快就能实现,但是最终花了将近两天的时间,遇到了各种坑和雷,特此记录,希望能帮助到有需要的朋友。
一、邮件发送的各种端口:
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)方法。
点赞(2)