EDM开发之二:SMTP服务器

SMTP服务器

服务器的搭建我就不做过多的叙述了,网上有很多,这里主要讲一下SMTP的工作原理和工作过程。

SMTP通常有两种工作模式:发送SMTP和接收SMTP。具体工作方式为:发送SMTP在接到用户的邮件请求后,判断此邮件是否为本地邮件,若是直接投送到用户的邮箱,否则向dns查询远端邮件服务器的MX纪录,并建立与远端接收SMTP之间的一个双向传送通道,此后SMTP命令由发送SMTP发出,由接收SMTP接收,而应答则反方面传送。一旦传送通道建立,SMTP发送者发送MAIL命令指明邮件发送者。如果SMTP接收者可以接收邮件则返回OK应答。SMTP发送者再发出RCPT命令确认邮件是否接收到。如果SMTP接收者接收,则返回OK应答;如果不能接收到,则发出拒绝接收应答(但不中止整个邮件操作),双方将如此重复多次。当接收者收到全部邮件后会接收到特别的序列,如果接收者成功处理了邮件,则返回OK应答即可。

下面是我个人对邮件在SMTP服务器文件夹中的旅行路径,如有错误请指正:

邮件发送分为同步发送和异步发送:

 1 /// <summary>
 2 /// 邮件设置
 3 /// </summary>
 4 /// <param name="toAddress">收件人地址</param>
 5 /// <param name="fromAddress">发件人地址</param>
 6 /// <param name="toName">收件人名字</param>
 7 /// <param name="fromName">发件人姓名</param>
 8 /// <param name="title">主题</param>
 9 /// <param name="body">正文</param>
10 /// <param name="isBodyHtml">正文是否为html格式</param>
11 public SendEmail(string toAddress, string fromAddress, string toName, string fromName, string title, string body, bool isBodyHtml)
12 {
13     mailMessage.From = new MailAddress(fromAddress, fromName, Encoding.GetEncoding(936));
14     if (toName.Equals(""))
15         mailMessage.To.Add(toAddress);
16     else
17         mailMessage.To.Add(new MailAddress(toAddress, toName, Encoding.GetEncoding(936)));
18 
19     mailMessage.Subject = title;
20     mailMessage.SubjectEncoding = Encoding.GetEncoding(936);
21 
22     mailMessage.Body = body;
23     mailMessage.IsBodyHtml = isBodyHtml;
24     mailMessage.BodyEncoding = Encoding.GetEncoding(936);
25 }
26 /// <summary>
27 /// 设置SMTP,并且将邮件发送出去
28 /// 所有参数都设置完成后再调用该方法
29 /// </summary>
30 /// <param name="address">发件人地址(必须为真实有效的email地址)</param>
31 /// <param name="password">发件人密码</param>
32 /// <param name="smtpHost">SMTP服务器地址,例如:smtp.163.com</param>
33 /// <param name="smtpPort">SMTP服务器的端口,一般为25</param>
34 /// <param name="isEnableSsl">SMTP服务器是否启用SSL加密</param>
35 /// <param name="priority">邮件的优先级</param>
36 /// <param name="UseDefaultCredentials">设置是否需要身份验证</param>
37 public void SetSmtp(string address, string password, string smtpHost, int smtpPort, bool isEnableSsl, MailPriority priority)
38 {
39     var smtp = new SmtpClient
40     {
41         DeliveryMethod = SmtpDeliveryMethod.Network,//电子邮件通过网络发送到SMTP服务器
42         Credentials = new NetworkCredential(address, password),
43         Host = smtpHost,
44         Port = smtpPort,
45         UseDefaultCredentials = true,
46         EnableSsl = isEnableSsl
47     };
48     mailMessage.Priority = priority;
49     //smtp.Send(mailMessage); //同步发送邮件
50     smtp.SendAsync(mailMessage, mailMessage.To.ToString());//异步发送邮件
51 }
SendEmail

除非检测SMTP的log日志文件,否则我们并不知道邮件是否发送成功,检测SMTP日志可以用logparser工具,他可以像sql那样通过查询语句来获得log的日志内容:

net start smtpsvc /启动smtp日志记录命令行/

 1 using LogQuery = MSUtil.LogQueryClass;
 2 using LogRecordSet = MSUtil.ILogRecordset;
 3 using TsvInputFormat = MSUtil.COMTSVInputContextClass;
 4 public class LogParser
 5 {
 6     /// <summary>      
 7     /// 计算日志条数    
 8     /// </summary>      
 9     public double GetLogCount(string headerFile, string logName)
10     {
11         double avgLockSec = 0;
12         var oLogQuery = new LogQuery();
13         var oTsvInputFormat = new TsvInputFormat { iHeaderFile = headerFile };
14         string query = "select * from '" + logName + "'";
15         LogRecordSet oRecordSet = oLogQuery.Execute(query, oTsvInputFormat);
16         if (!oRecordSet.atEnd())
17         {
18             double item = 0;
19             if (!oRecordSet.getRecord().isNull(0))
20             {
21                 item = double.Parse(oRecordSet.getRecord().getValue(0).ToString());
22             }
23             avgLockSec = item;
24         }
25         oRecordSet.close();
26         return avgLockSec;
27     }
28 }
LogParser

根据上面图片我们知道,发送失败的Email会放到Drop和BadEmail两个文件夹中,所以只要监测两个文件夹,有文件进来就是发送失败的邮件:

 1 public static class MyFileSystemWatcher
 2 {
 3     [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
 4     public static void WatcherStrat(string path)
 5     {
 6         var watcher = new FileSystemWatcher { Path = path, Filter = "*.*" };
 7         watcher.Created += new FileSystemEventHandler(OnProcess);
 8         watcher.EnableRaisingEvents = true;
 9         watcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Security | NotifyFilters.Size;
10         watcher.IncludeSubdirectories = true;
11     }
12     public static void OnProcess(object source, FileSystemEventArgs e)
13     {
14         switch (e.ChangeType)
15         {
16             case WatcherChangeTypes.Created:
17                 OnCreated(source, e);
18                 break;
19         }
20     }
21     public static void OnCreated(object source, FileSystemEventArgs e)
22     {
23         Console.WriteLine("文件改变事件{0}文件路径{1}文件名{2}", e.ChangeType, e.FullPath, e.Name);
24     }
25     public static void OnChanged(object source, FileSystemEventArgs e)
26     {
27         Console.WriteLine("文件改变事件{0}文件路径{1}文件名{2}", e.ChangeType, e.FullPath, e.Name);
28     }
29     public static void OnDeleted(object source, FileSystemEventArgs e)
30     {
31         Console.WriteLine("文件删除事件{0}文件路径{1}文件名{2}", e.ChangeType, e.FullPath, e.Name);
32     }
33     public static void OnRenamed(object source, RenamedEventArgs e)
34     {
35         Console.WriteLine("文件重命名事件{0}文件路径{1}文件名{2}", e.ChangeType, e.FullPath, e.Name);
36     }
37     public static void GetFilesSystemRights(string path)
38     {
39         //给文件添加"Everyone,Users"用户组的完全控制权限  
40         var fi = new FileInfo(path);
41         System.Security.AccessControl.FileSecurity fileSecurity = fi.GetAccessControl();
42         fileSecurity.AddAccessRule(new FileSystemAccessRule("Everyone", FileSystemRights.FullControl, AccessControlType.Allow));
43         fileSecurity.AddAccessRule(new FileSystemAccessRule("Users", FileSystemRights.FullControl, AccessControlType.Allow));
44         fi.SetAccessControl(fileSecurity);
45         //给文件所在目录添加"Everyone,Users"用户组的完全控制权限  
46         var di = new DirectoryInfo(path);
47         System.Security.AccessControl.DirectorySecurity dirSecurity = di.GetAccessControl();
48         dirSecurity.AddAccessRule(new FileSystemAccessRule("Everyone", FileSystemRights.FullControl, AccessControlType.Allow));
49         dirSecurity.AddAccessRule(new FileSystemAccessRule("Users", FileSystemRights.FullControl, AccessControlType.Allow));
50         di.SetAccessControl(dirSecurity);
51 
52     }
53 }
文件监测

在Global.asax文件中添加MyFileSystemWatcher.WatcherStrat("文件夹路径");以便在服务启动时就开始监测文件夹。

.BAD文件是邮件的实际内容;

.BDP是无用信息的回集;

.BDR文件显示了邮件没有被发送的原因

posted @ 2015-04-08 16:14  刺激雄  阅读(461)  评论(0编辑  收藏  举报