上一篇文章说的是告警短信发送,这种效率非常高,缺点也很明显,需要购买特定的短信硬件设备支持才行,而且每条短信都要收费,如果要求发送的短信数量特别多,这个费用常年累月下来也是不少的,客户就不愿意了,所以又衍生出了另外一种方式,那就是发送报警邮件,现在智能手机人人都有,对应系统的管理员或者保安当然都有,手机上安装一个邮箱软件,收到邮件后立即通知提醒,不错过每一个重要的警情信息,这样就完美的取代了告警短信转发的方案。而且还可以每隔一段时间,统计该时间段内的所有警情信息,导出到xls文件报表,以文件附件的形式邮件发出去,这样用户还可以在任意地点收到整理好的警情记录,这个就非常的人性化了。
大约在2013年左右就做过类似的功能,使用的也是标准的POP3邮件发送协议,其实就是tcp通信,按照标准协议解析和应答,然后将邮件内容和附件一起发出去,最开始做的很粗糙,后面随着真实项目的应用需求不断变化,该组件也在不断的迭代发展,比如多线程发送邮件,多个收件人,多个附件,html格式的邮件内容。这个富文本格式的邮件内容,可以直接将报警信息组合成表格形式的内容,这样用户连附件都不用打开,直接内容就是table表格的形式,用起来着实方便。
本系统支持邮件转发,前提是对应的邮箱账号需要开通 POP3/SMTP 等服务,按照图示开启即可,一般开启后会设置独立的管理密码,记得在系统设置那边的邮件转发,填写密码的时候要填的是独立管理密码,而不是邮箱号的密码,这个机制和任何第三方邮箱管理软件都一样。
void SendEmailThread::run()
{
while (!stopped) {
int count = contents.count();
if (count > 0) {
mutex.lock();
QString content = contents.takeFirst();
QString fileName = fileNames.takeFirst();
mutex.unlock();
QString result;
QStringList list = sendEmailAddr.split("@");
QString tempSMTP = list.at(1).split(".").at(0);
int tempPort = 25;
//QQ邮箱端口号为465,必须启用SSL协议.
if (tempSMTP.toUpper() == "QQ") {
tempPort = 465;
}
SmtpClient smtp(QString("smtp.%1.com").arg(tempSMTP), tempPort, tempPort == 25 ? SmtpClient::TcpConnection : SmtpClient::SslConnection);
smtp.setUser(sendEmailAddr);
smtp.setPassword(sendEmailPwd);
//构建邮件主题,包含发件人收件人附件等.
MimeMessage message;
message.setSender(new EmailAddress(sendEmailAddr));
//逐个添加收件人
QStringList receiver = receiveEmailAddr.split(';');
for (int i = 0; i < receiver.size(); ++i) {
message.addRecipient(new EmailAddress(receiver.at(i)));
}
//构建邮件标题
message.setSubject(emialTitle);
//构建邮件正文
MimeHtml text;
text.setHtml(content);
message.addPart(&text);
//构建附件-报警图像
if (fileName.length() > 0) {
QStringList attas = fileName.split(";");
foreach (QString tempAtta, attas) {
QFile *file = new QFile(tempAtta);
if (file->exists()) {
message.addPart(new MimeAttachment(file));
}
}
}
if (!smtp.connectToHost()) {
result = "邮件服务器连接失败";
} else {
if (!smtp.login()) {
result = "邮件用户登录失败";
} else {
if (!smtp.sendMail(message)) {
result = "邮件发送失败";
} else {
result = "邮件发送成功";
}
}
}
smtp.quit();
if (!result.isEmpty()) {
emit receiveEmailResult(result);
}
msleep(1000);
}
msleep(100);
}
stopped = false;
}
void SendServer::checkEmail()
{
int count = listEmail.count();
if (count == 0) {
return;
}
//邮件内容,无论多长都可以拼在一起发送,
用来换行显示
QStringList listContent, listFileName;
for (int i = 0; i < count; ++i) {
QString str = listEmail.takeFirst();
if (str.contains("|")) {
QStringList list = str.split("|");
QString content = list.at(0);
QString fileName = list.at(1);
if (!content.isEmpty()) {
listContent << content;
}
if (!fileName.isEmpty()) {
listFileName << fileName;
}
} else {
listContent.append(str);
}
}
//构建html字符串
QStringList html;
if (listContent.count() > 0) {
//将字符串转换为表格形式,先取出字段名,然后取出内容
//位号: AT-40002 控制器: 1#调度室控制器 探测器: 2#阀站CO 触发值: 78.7 %LEL 类型: 浓度上限报警 时间: 2019-02-24 21:01:30
//位号: AT-40003 控制器: 1#调度室控制器 探测器: 3#阀站CO 触发值: 57 %VOL 类型: 浓度下限报警 时间: 2019-02-24 21:01:30
//位号: AT-40004 控制器: 1#调度室控制器 探测器: 4#阀站CO 触发值: 88 PPM 类型: 浓度下限报警 时间: 2019-02-24 21:01:30
//先取出字段名
QString str = listContent.first();
QStringList list = str.split(" ");
QStringList columnNames;
foreach (QString str, list) {
columnNames << str.split(": ").first();
}
//字段宽度
QList<int> columnWidth;
columnWidth << 150 << 200 << 180 << 130 << 160 << 200;
//再遍历取出所有数据
QList<QStringList> rowContents;
foreach (QString str, listContent) {
QStringList list = str.split(" ");
QStringList rowContent;
foreach (QString temp, list) {
rowContent << temp.split(": ").last();
}
rowContents << rowContent;
}
//表格开始
html.append("");
//标题字段名称
QString title;
for (int i = 0; i < columnNames.count(); ++i) {
title += QString("%2 ")
.arg(columnWidth.at(i)).arg(columnNames.at(i));
}
html.append(QString("%1 ").arg(title));
//内容
for (int j = 0; j < rowContents.count(); j++) {
QString row;
QStringList rowContent = rowContents.at(j);
for (int i = 0; i < rowContent.count(); ++i) {
row += QString("%2 ")
.arg(columnWidth.at(i)).arg(rowContent.at(i));
}
html.append(QString("%1 ").arg(row));
}
//表格结束
html.append("
");
}
//将邮件内容和附件链接追加到发送报警邮件线程中
SendEmailThread::Instance()->setSendEmailAddr(AppConfig::SendEmailAddr);
SendEmailThread::Instance()->setSendEmailPwd(AppConfig::SendEmailPwd);
SendEmailThread::Instance()->setReceiveEmailAddr(AppConfig::ReceiveEmailAddr);
SendEmailThread::Instance()->append(html.join(""), listFileName.join(";"));
//SendEmailThread::Instance()->append(listContent.join("
"), listFileName.join(";"));
}