zoukankan      html  css  js  c++  java
  • 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文件显示了邮件没有被发送的原因

  • 相关阅读:
    NFS
    Linux ISO镜像挂载
    Python3.6 提示 ModuleNotFoundError: No module named '_ssl' 模块问题
    mysql 5.7 ERROR 1054(42S22) Unknown column 'password' in ‘field list’ 报错
    Redis + keepalived 高可用行配置检测脚本
    Linux 文件大小查找排序
    查看 Centos 7 的MAC 地址
    Discuz 论坛 (LAMP环境)
    SVN
    systemctl
  • 原文地址:https://www.cnblogs.com/lx-bk/p/4389580.html
Copyright © 2011-2022 走看看