📄 email.cpp
字号:
/** * @file email.cpp * @brief 发送电子邮件包装,函数的实现 * @author 泥偶 * @since 2003-09-12 * @date 2003-09-23 */extern "C"{ #include <errno.h> #include <sys/time.h> #include <sys/uio.h> #include <sys/wait.h> #include <unistd.h>}#include <cstddef>#include <fstream>#include "email.hpp"namespace x{ bool Email::setTo(const xstring& inAddress) { if (!inAddress.isEmail()) { return false; } if (!this->mailTo.empty()) { this->mailTo += ','; } this->mailTo += inAddress; return true; } bool Email::setCc(const xstring& inAddress) { if (!inAddress.isEmail()) { return false; } if (!this->mailCc.empty()) { this->mailCc += ','; } this->mailCc += inAddress; return true; } bool Email::setBcc(const xstring& inAddress) { if (!inAddress.isEmail()) { return false; } if (!this->mailBcc.empty()) { this->mailBcc += ','; } this->mailBcc += inAddress; return true; } bool Email::setFrom(const xstring& inAddress) { if (!inAddress.isEmail()) { return false; } this->mailFrom = inAddress; return true; } bool Email::setSubject(const xstring& inSubject) { if (inSubject.trim().empty()) { return false; } this->mailSubject = inSubject; return true; } bool Email::setText(const xstring& inText) { if (inText.trim().empty()) { return false; } this->mailText = inText; return true; } bool Email::setHTML(const xstring& inHTML) { if (inHTML.trim().empty()) { return false; } this->mailHTML = inHTML; return true; } bool Email::addAttachment( const xstring& inMessage, const xstring& inName, const xstring& inContentType ) { if (inMessage.trim().empty()) { return false; } Attachment attachment; attachment.ctype = inContentType; attachment.message = inMessage; attachment.encode = ""; attachment.name = inName; this->mailAttachments.push_back(attachment); return true; } bool Email::addAttachmentFile(const xstring& inFileName) { xstring message; char c; std::ifstream file(inFileName.c_str()); if (!file) { return false; } while (file.get(c)) { message += c; } return this->addAttachment(message, inFileName.basename(), this->getContentType(inFileName)); } // 自动关闭文件 bool Email::send(void) { // 设置邮件头为空 xstring mailHeader; // 添加抄送人 if (!this->mailCc.empty()) { mailHeader += "Cc: " + this->mailCc + "\n"; } // 添加秘密抄送人 if (!this->mailBcc.empty()) { mailHeader += "Bcc: " + this->mailBcc + "\n"; } // 添加发件人 if (!this->mailFrom.empty()) { mailHeader += "From: " + this->mailFrom + "\n"; } // 邮件正文 if (!this->mailText.empty()) { this->addAttachment(this->mailText, "", "text/plain"); } // HTML格式邮件正文 if (!this->mailHTML.empty()) { this->addAttachment(this->mailHTML, "", "text/html"); } mailHeader += "MIME-Version: 1.0\n" + this->buildMultipart(); return this->mail(this->mailTo, this->mailSubject, "", mailHeader); } // Email::send()//============================================================================ xstring Email::getContentType(const xstring& inFilename) { xstring extension; xstring basename = inFilename.basename(); xstring::size_type idx = basename.rfind('.'); if (xstring::npos != idx) { extension = basename.substr(idx + 1); } if ("gif" == extension) { return "image/gif"; } if ("gz" == extension) { return "application/x-gzip"; } if ("htm" == extension || "html" == extension) { return "text/html"; } if ("jpe" == extension || "jpeg" == extension || "jpg" == extension) { return "image/jpeg"; } if ("png" == extension) { return "image/png"; } if ("tar" == extension) { return "application/x-tar"; } if ("txt" == extension) { return "text/plain"; } if ("zip" == extension) { return "application/x-zip-compressed"; } return "application/octet-stream"; } // Email::getContentType() // Build message parts of an multipart mail xstring Email::buildMessage(const Attachment& inAttachment) { return "Content-Type: " + inAttachment.ctype + (inAttachment.name.empty() ? "" : "; name=\"" + inAttachment.name + "\"") + "\nContent-Transfer-Encoding: base64\n\n" + inAttachment.message.base64_encode().chunk_split() + "\n"; } // Build a multipart mail xstring Email::buildMultipart(void) { struct timeval now; gettimeofday(&now, NULL); int microtime = now.tv_sec * 1000000 + now.tv_usec; xstring boundary = 'b' + xstring(microtime).md5(); xstring multipart = "Content-Type: multipart/mixed; boundary = " + boundary + "\n\nThis is a MIME encoded message.\n\n--" + boundary; for (int i = this->mailAttachments.size() - 1; i >= 0; --i) { multipart += "\n" + this->buildMessage(this->mailAttachments[i]) + "--" + boundary; } multipart += "--\n"; return multipart; } // 调用sendmail发送邮件 bool Email::mail( const xstring& to, const xstring& subject, const xstring& message, const xstring& additional_headers ) { const xstring sendmail_path = "/usr/sbin/sendmail"; // 环境 char* env_init[] = { "USER=unknown", "PATH=/tmp", NULL }; int fd[2]; pid_t pid; if (pipe(fd) < 0) // 创建半双工管道 { return false; // 坏掉了 } switch (pid = fork()) // 创建子进程 { case -1 : // 坏掉了 close(fd[0]); // 关闭半双工管道读的一端 close(fd[1]); // 关闭半双工管道写的一端 return false; case 0 : // 子进程 close(fd[1]); // 关闭半双工管道写的一端 if (fd[0] != STDIN_FILENO) { // 把半双工管道读的一端和标准输入捆在一起 if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) { exit(1); // 坏掉了 } close(fd[0]); // dup2以后这个东东就用不着了 } // 运行sendmail if (execle(sendmail_path.c_str(), "sendmail", "-t", "-i", (char*)0, env_init) < 0) { exit(1); // 坏掉了 } exit(1); // 执行不到这里 default : // 父进程 close(fd[0]); // 关闭半双工管道读的一端 writen(fd[1], "To: " + to + "\n"); writen(fd[1], "Subject: " + subject + "\n"); writen(fd[1], additional_headers + "\n"); writen(fd[1], message + "\n"); close(fd[1]); // 关闭半双工管道,毁尸灭迹 if (waitpid(pid, NULL, 0) < 0) // 等子进程死掉 { return false; // 坏掉了 } return true; } } // Email::mail() /// 向文件描述符写,保证写出指定的字节数 ssize_t Email::writen(int d, const xstring& str) { return writen(d, str.data(), str.size()); } /// 向文件描述符写n字节写,保证写出指定的字节数 ssize_t Email::writen(int d, const void* buf, size_t nbytes) { size_t nleft; size_t nwritten; const char* ptr; ptr = static_cast<const char*>(buf); // 不能对void指针进行算术运算 nleft = nbytes; while (nleft > 0) { nwritten = write(d, ptr, nleft); if (nwritten <= 0) { if (EINTR == errno) { nwritten = 0; } else { return nwritten; } } nleft -= nwritten; ptr += nwritten; } return nbytes; }} // namespace x
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -