用C++发邮件
近段时间,实验室电脑的IP频繁地改变,搞得想用远程偷下懒都不行。这时想到的解决方法有:静态IP,动态域名,自己解决。静态IP虽然可以自己指定,但一关机后,与对方冲突就完了,作罢。免费的动态域名又要手机认证,也作罢。最后只能自己解决。解决方案是写一个程序不断地检测本机IP,如果改变了,就发邮件通知。检测本机IP很简单,就略过。这里介绍下怎样发邮件吧。
发邮件前,需要理解SMTP(Simple Mail Transfer Protocol)。SMTP是电子邮件从客户机传输到服务器或从某一个服务器传输到另一个服务器使用的传输协议。SMTP 是请求/响应协议,命令和响应都是基于 ASCII 文本,并以 CR 和 LF 符结束。响应包括一个表示返回状态的三位数字代码。在 TCP 协议 25 端口监听连接请求。其命令如下:
SMTP命令 | 命令说明 |
HELO <domain><CRLF> | 识别发送方到接收SMTP的一个HELO命令 |
AUTH LOGIN<CRLF> | 登陆服务器的命令。在这条命令之后,要发送用Base64编码后的用户名与密码进行登陆 |
MAIL FROM:<reverse-path><CRLF> | <reverse-path>为发送者地址。此命令告诉接收方一个新邮件发送的开始,并对所有的状态和缓冲区进行初始化。此命令开始一个邮件传输处理,最终完成将邮件数据传送到一个或多个邮箱中。 |
RCPT TO:<forward-path><CRLF> | <forward-path>标识各个邮件接收者的地址 |
DATA <CRLF> | 接收SMTP将把其后的行为看作邮件数据去处理,以<CRLF>.<CRLF>标识数据的结尾。 |
REST <CRLF> | 退出/复位当前的邮件传输 |
NOOP <CRLF> | 要求接收SMTP仅做OK应答。(用于测试) |
QUIT <CRLF> | 要求接收SMTP返回一个OK应答并关闭传输。 |
VRFY <string> <CRLF> | 验证指定的邮箱是否存在,由于安全因素,服务器多禁止此命令。 |
EXPN <string> <CRLF> | 验证给定的邮箱列表是否存在,扩充邮箱列表,也常禁止使用。 |
HELP <CRLF> | 查询服务器支持什么命令 |
了解了这些命令后, 就可以发邮件了。发一封简单邮件的交互图如下,其中邮箱使用163邮箱:
C++发邮件的实现表示如下:

//author: Zero //facade of function send()
void Send(SOCKET& s, string& data) {
if( send(s, data.c_str(), data.length(), 0) == SOCKET_ERROR ) {
cerr<<"send data \""<<data<<"\" error"<<endl;
}
} //facade of function recv()
void Recv(SOCKET& s, char* buf, int len) {
memset(buf, 0, len);
if( recv(s, buf, len, 0) == SOCKET_ERROR ) {
cerr<<"error, while receiving data"<<endl;
}
} string Base64Encode(const string& src) {
int i, j, srcLen = src.length();
string dst(srcLen / 3 * 4 + 4, 0);
for(i = 0, j= 0; i <=srcLen - 3; i+=3, j+=4) {
dst[j] = (src[i] & 0xFC) >> 2;
dst[j+1] = ((src[i] & 0x03) << 4) + ((src[i+1] & 0xF0) >> 4);
dst[j+2] = ((src[i+1] & 0x0F) << 2) + ((src[i+2] & 0xC0) >> 6);
dst[j+3] = src[i+2] & 0x3F;
}
if( srcLen % 3 == 1 ) {
dst[j] = (src[i] & 0xFC) >> 2;
dst[j+1] = ((src[i] & 0x03) << 4);
dst[j+2] = 64;
dst[j+3] = 64;
j += 4;
}
else if( srcLen % 3 == 2 ) {
dst[j] = (src[i] & 0xFC) >> 2;
dst[j+1] = ((src[i] & 0x03) << 4) + ((src[i+1] & 0xF0) >> 4);
dst[j+2] = ((src[i+1] & 0x0F) << 2);
dst[j+3] = 64;
j+=4;
} static unsigned char *base64 = (unsigned char*)("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=");
for(i = 0; i < j; ++i) { //map 6 bit value to base64 ASCII character
dst[i] = base64[(int)dst[i]];
} return dst;
} bool SendEmail(const string& smtpServer, const string& username, const string& pw, const string& to, const string& data) {
hostent *ph = gethostbyname(smtpServer.c_str());
if( ph == NULL ) {
cerr<<"no host: "<<smtpServer<<endl;
return false;
} sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(25); //port of SMTP
memcpy(&sin.sin_addr.S_un.S_addr, ph->h_addr_list[0], ph->h_length); //connect to the mail server
SOCKET s = socket(PF_INET, SOCK_STREAM, 0);
if( connect(s, (sockaddr*)&sin, sizeof(sin)) ) {
cerr<<"failed to connect the mail server"<<endl;
return false;
} //
char recvBuffer[1024];
Recv(s, recvBuffer, sizeof(recvBuffer)); //wait for greeting message
Send(s, "HELO " + smtpServer + "\r\n");
Recv(s, recvBuffer, sizeof(recvBuffer)); //should recv "250 OK" //start to log in
Send(s, (string)"auth login\r\n");
Recv(s, recvBuffer, sizeof(recvBuffer)); //should recv "334 username:"(This is the decode message) Send(s, Base64Encode(username) + "\r\n");
Recv(s, recvBuffer, sizeof(recvBuffer));
if( string(recvBuffer).substr(0, 3) != "334" ) {
cout<<"username is error!"<<endl;
return false;
} Send(s, Base64Encode(pw) + "\r\n");
Recv(s, recvBuffer, sizeof(recvBuffer));
if( string(recvBuffer).substr(0, 3) != "235") {
cout<<"password error"<<endl;
return false;
} //Set sender
Send(s, "mail from:<" + username + ">\r\n");
Recv(s, recvBuffer, sizeof(recvBuffer)); //should recv "250 Mail OK" //set receiver
Send(s, "rcpt to:<" + to + ">\r\n");
Recv(s, recvBuffer, sizeof(recvBuffer)); //should recv "250 Mail OK" //send data
Send(s, (string)"data\r\n");
Recv(s, recvBuffer, sizeof(recvBuffer)); //should recv "354 End data with <CR><LF>.<CR><LF>"
Send(s, "to:" + to + "\r\n" + "subject:the newest IP\r\n\r\n" + data + "\r\n.\r\n");
Recv(s, recvBuffer, sizeof(recvBuffer)); Send(s, (string)"quit\r\n");
Recv(s, recvBuffer, sizeof(recvBuffer));
closesocket(s);
return true;
}

用C++发邮件的更多相关文章
- # PHP - 使用PHPMailer发邮件
PHPMailer支持多种邮件发送方式,使用起来非常简单 1.下载PHPMailer https://github.com/PHPMailer/PHPMailer,下载完成加压后, 把下边的两个文件复 ...
- Linux发邮件之mail命令
一.mail命令 1.配置 vim /etc/mail.rc 文件尾增加以下内容 set from=1968089885@qq.com smtp="smtp.qq.com" set ...
- 测试MailUtils,作用是发邮件
package cn.itcast.test; import java.io.IOException; import javax.mail.MessagingException; import jav ...
- SQL Server定时自动抓取耗时SQL并归档数据发邮件脚本分享
SQL Server定时自动抓取耗时SQL并归档数据发邮件脚本分享 第一步建库和建表 USE [master] GO CREATE DATABASE [MonitorElapsedHighSQL] G ...
- 学习linux之用mail命令发邮件
背景 这两天工作比较闲,网上各种冲浪(这个词暴露我的网龄了).看到一位大神的文章更闲 <>.端详一番,原来是用R语言拼接字符串后用shell命令发出去.发现shell命令既然还能直接发邮件 ...
- linux mail利用外部邮箱地址发邮件
mail命令发送邮件需要sendmail或postfix服务 三种常用格式发信 mail -s "标题" xxx@xxx.xxx #第一种方法,你可以把当前shell当成编辑器来用 ...
- 打电话,发短信,发邮件,app跳转
1.打电话 - (IBAction)callPhone1:(id)sender { NSURL *url = [NSURL URLWithString:@"tel://18500441739 ...
- iOS中如何切换到发短信、打电话、发邮件
我们在做APP的时候,难免会遇到需要调用短信,电话等程序的时候.如美团. 当然,这些都只是一些简单的方法就可以实现,但是时间久了也会淡忘,所以想写这边博客.一是为了再捡起来复习一下,另一个相当于留个备 ...
- 发邮件 和 excel导出中文文件名
/** * 发邮件 * @param email * @param subject * @param body * @throws UnsupportedEncodingException */ pu ...
- 【知识积累】JavaMail实现发邮件功能
一.前言 今天闲来没事,想着通过程序来给别人发邮件.于是,上网搜了一下,相应的资料也很多,刚开始完成了邮件的简单发送,后来想如何能发送附件,继续寻找 答案,但是遇到了一个问题是当我使用txt类型作为附 ...
随机推荐
- Segmentation fault(core dumped) 调试
ReadingList: https://mytechrants.wordpress.com/2009/05/22/debugging-a-segmentation-fault-using-gdb/ ...
- HDU 5289 Assignment(单调队列)
题意:给T足数据,然后每组一个n和k,表示n个数,k表示最大同意的能力差,接下来n个数表示n个人的能力,求能力差在k之内的区间有几个 分析:维护一个区间的最大值和最小值,使得他们的差小于k,于是採用单 ...
- 在.NET中怎样取得代码行数
文章目的 介绍在.NET中取得代码行数的方法 代码 [STAThread] static void Main(string[] args) { ReportError("Yay!" ...
- [LeetCode][Java] Best Time to Buy and Sell Stock IV
题目: Say you have an array for which the ith element is the price of a given stock on day i. Design a ...
- 【软件创意】智能Goals (android)
智能Goals 软件创意核心思想:实现你的愿望. 功能概要:帮助记录奋斗了的历程.实现你的愿望.可以是跑步减肥,每天阅读,交际,存钱买房.满足各种记录需要,目标可以是完成多长时间,可以用计时器:可以 ...
- wamp中apache2.4.9配置httpd.conf允许外部访问
安装最新的wamp后发现通过外部网络无法访问本机的apache.在网上查询了相关问题,所有的答案基本都是说在httpd.conf文件中加入语句Allow from all.但是这些对应的是ap ...
- JAVA传输概念
1.VO(View Object):视图对象,用于展示在前台界面. 2.DTO(Data Transfer Object):数据传输对象,泛指用于展示层与服务层之间的数据传输对象. 3. DTO和VO ...
- Linux 中如何查询和卸载已安装的软件
Linux 中如何查询和卸载已安装的软件 Linux软件的安装和卸载一直是困扰许多新用户的难题.在Windows中,我们可以使用软件自带的安装卸载程序或在控制面板中的“添加/删除程序” 来实现.与其相 ...
- java gc小结
java的内存结构: 1. 堆: java所有通过new新建的对象都是在堆上进行分配的; 根据不同的垃圾回收算法, 堆的结构也不相同, 如果采用的是分代垃圾回收, 那么堆就分为年轻代和年老代两部分. ...
- (转)MongoDB在mongo控制台下的基本使用命令
成功启动MongoDB后,再打开一个命令行窗口输入mongo,就可以进行数据库的一些操作. 输入help可以看到基本操作命令: show dbs:显示数据库列表 show collections:显示 ...