优秀的编程知识分享平台

网站首页 > 技术文章 正文

C#上位机基于SMTP实现邮件报警通知

nanyue 2025-05-10 23:58:12 技术文章 3 ℃

今天跟大家分享一下C#上位机如何基于SMTP协议实现邮件报警通知。

SMTP是一种提供可靠且有效的电子邮件传输的协议,是建立在FTP文件传输服务上的一种邮件服务,主要用于系统之间的邮件信息传递,并提供有关来信的通知。

一、准备邮箱

首先我们要准备2个邮箱,一个作为发送者邮箱,一个作为接收者邮箱。

发送者邮箱需要开启SMTP相关服务,这个一般在邮箱的设置中,可以找到。

开启服务之后,会生成一个授权码,这个授权码很重要,后面代码中会使用到。

二、代码实现

那么我们如何通过代码来实现呢?

首先我们需要创建一个实体类,这个实体类中包含了发送邮箱的相关信息:

public class EmailInfo
{
    /// <summary>
    /// 发送者
    /// </summary>
    public string MailFrom { get; set; }
    /// <summary>
    /// 收件人
    /// </summary>
    public string[] MailToArray { get; set; }
    /// <summary>
    /// 抄送
    /// </summary>
    public string[] MailCcArray { get; set; }
    /// <summary>
    /// 标题
    /// </summary>
    public string MailSubject { get; set; }
    /// <summary>
    /// 正文
    /// </summary>
    public string MailBody { get; set; }
    /// <summary>
    /// 发件人密码
    /// </summary>
    public string MailPwd { get; set; }
    /// <summary>
    /// SMTP邮件服务器
    /// </summary>
    public string Host { get; set; }
    /// <summary>
    /// 正文是否是html格式
    /// </summary>
    public bool IsbodyHtml { get; set; }
    /// <summary>
    /// 附件
    /// </summary>
    public string[] AttachmentsPath { get; set; }
}

二、然后我们再创建一个EmailHelper类,在该类中编写一个Send方法:

public class EmailHelper
{
    /// <summary>
    /// 发送邮件
    /// </summary>
    /// <returns></returns>
    public static void Send(EmailInfo email)
    {
        //使用指定的邮件地址初始化MailAddress实例
        MailAddress maddr = new MailAddress(email.MailFrom);
        //初始化MailMessage实例
        MailMessage myMail = new MailMessage();
        //向收件人地址集合添加邮件地址
        if (email.MailToArray != null)
        {
            for (int i = 0; i < email.MailToArray.Length; i++)
            {
                myMail.To.Add(email.MailToArray[i].ToString());
            }
        }
        //向抄送收件人地址集合添加邮件地址
        if (email.MailCcArray != null)
        {
            for (int i = 0; i < email.MailCcArray.Length; i++)
            {
                myMail.CC.Add(email.MailCcArray[i].ToString());
            }
        }
        //发件人地址
        myMail.From = maddr;
        //电子邮件的标题
        myMail.Subject = email.MailSubject;
        //电子邮件的主题内容使用的编码
        myMail.SubjectEncoding = Encoding.UTF8;
        //电子邮件正文
        myMail.Body = email.MailBody;
        //电子邮件正文的编码
        myMail.BodyEncoding = Encoding.Default;
        myMail.Priority = MailPriority.High;
        myMail.IsBodyHtml = email.IsbodyHtml;
        //在有附件的情况下添加附件
        try
        {
            if (email.AttachmentsPath != null && email.AttachmentsPath.Length > 0)
            {
                Attachment attachFile = null;
                foreach (string path in email.AttachmentsPath)
                {
                    attachFile = new Attachment(path);
                    myMail.Attachments.Add(attachFile);
                }
            }
        }
        catch (Exception ex)
        {
            throw new Exception("在添加附件时有错误:" + ex.Message);
        }
        SmtpClient smtp = new SmtpClient();
        smtp.EnableSsl = true;
        //指定发件人的邮件地址和密码以验证发件人身份
        smtp.Credentials = new NetworkCredential(email.MailFrom, email.MailPwd);
        //设置SMTP邮件服务器
        smtp.Host = email.Host;
        try
        {
            //将邮件发送到SMTP邮件服务器
            smtp.Send(myMail);
        }
        catch (SmtpException ex)
        {
            throw new Exception("发送邮件出错:" + ex.Message);
        }
    }
}

三、应用场景

我们结合前面介绍过的沿信号检测来做个报警发送邮件到指定邮箱的案例。

假设西门子200Smart PLC中,V100.0这个变量是循环泵故障信号,当检测到V100.0由False变成True时,发送一个邮件到邮箱中,代码编写如下:

1、上升沿检测代码:

/// <summary>
/// 带消抖处理的上升沿检测器(精确到毫秒级)
/// </summary>
public class DebouncedRisingEdgeDetector
{
    private bool _previousState;
    private DateTime _lastTriggerTime = DateTime.MinValue;
    private readonly int _debounceMs;
    private readonly object _lock = new object();
    /// <summary>
    /// 初始化消抖检测器
    /// </summary>
    /// <param name="debounceMilliseconds">消抖时间(毫秒)</param>
    /// <param name="initialState">初始输入状态</param>
    public DebouncedRisingEdgeDetector(int debounceMilliseconds, bool initialState = false)
    {
        _debounceMs = debounceMilliseconds > 0 ? debounceMilliseconds : 10;
        _previousState = initialState;
    }
    /// <summary>
    /// 检测输入信号的有效上升沿
    /// </summary>
    public bool CheckForRisingEdge(bool currentState)
    {
        lock (_lock)
        {
            bool edgeDetected = false;
            bool potentialEdge = !_previousState && currentState;
            if (potentialEdge)
            {
                TimeSpan elapsed = DateTime.UtcNow - _lastTriggerTime;
                if (elapsed.TotalMilliseconds > _debounceMs)
                {
                    edgeDetected = true;
                    _lastTriggerTime = DateTime.UtcNow;
                }
            }
            _previousState = currentState;
            return edgeDetected;
        }
    }
    /// <summary>
    /// 重置检测器状态
    /// </summary>
    public void Reset(bool initialState = false)
    {
        lock (_lock)
        {
            _previousState = initialState;
            _lastTriggerTime = DateTime.MinValue;
        }
    }
}

二、报警检测代码,如下所示:

public FrmMain()
{
    InitializeComponent();
    this.siemens = new Plc(CpuType.S7200Smart, "192.168.2.150", 0, 0);
    try
    {
        this.siemens.Open();
        //如果连接成功,开启多线程检测
        cts = new CancellationTokenSource();
        Task.Run(() =>
        {
            AlarmCheck();
        });
    }
    catch (Exception)
    {
        MessageBox.Show("PLC连接失败");
    }
}
private Plc siemens;
private CancellationTokenSource cts;
private DebouncedRisingEdgeDetector edgeCheck = new DebouncedRisingEdgeDetector(50, false);
private void AlarmCheck()
{
    while (!cts.IsCancellationRequested)
    {
        bool result = Convert.ToBoolean(siemens.Read("DB1.DBX100.0"));
        bool check = edgeCheck.CheckForRisingEdge(result);
        //检测到上升沿
        if (check)
        {
            Task.Run(() =>
            {
                EmailInfo email = new EmailInfo();
                email.MailFrom = "94693xxxxx@qq.com";
                //此处填写发送邮箱的授权码,非登录密码
                email.MailPwd = "XXXXXXXXXX";
                email.MailSubject = "循环泵故障报警";
                email.MailBody = "循环泵故障报警,报警时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                email.IsbodyHtml = false;
                email.Host = "smtp.qq.com";
                email.MailToArray = new string[] { "393350xxxx@qq.com" };
                EmailHelper.Send(email);
            });
        }
    }
}

三、测试结果如下:

当PLC中V100.0由False变成True的时候,邮箱中收到一封邮件:

手机上也能收到邮件推送:

最近发表
标签列表