用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类型作为附 ...
随机推荐
- Redis安装过程
Redis在windows下安装过程 学习了:https://www.cnblogs.com/M-LittleBird/p/5902850.html 学习了:http://www.runoob.com ...
- git pull出现fatal: unable to access 'https://github.com/XXX/YYY.git'
用cmd 发现ping不同 github.com Ping不通,这时候,只需要在host文件里做些修改就可以,首先,定位到路径 C:\Windows\System32\drivers\etc 找到ho ...
- 百度地图SDK调试SDKInitializer.initialize(getApplicationContext())错误
首先描写叙述下问题出现的原因.開始的时候写了一个百度地图SDK的demo来试功能,由于最開始用的是Eclipse自带的AVD来调试,一切正常. 都能够正常验证,可是由于受不了重复的重新启动AVD设备, ...
- vue2.0 自定义 侧滑删除(LeftSlider)组件
1.自定义侧滑删除组件 LeftSlider.vue <!-- 侧滑删除 组件 --> <template> <div class="delete"& ...
- css控制打印时只显示指定区域
CreateTime--2017年9月26日08:16:04 Author:Marydon css控制打印时只显示指定区域 思路: 1.使用打印命令@media print: 2.控制执行打印命令 ...
- Spring延迟加载
如下内容引用自:http://www.cnblogs.com/wcyBlog/p/3756624.html 1.Spring中lazy-init详解ApplicationContext实现的默认行为就 ...
- Cent OS下发送邮件
首先安装发送邮件的服务: yum install -y sendmail 安装完成之后在安装mutt yum install -y mutt 安装完成之后我们就可以发送邮件了 mutt tes ...
- Unity光滑与粗糙的材质——相似于生锈的金属表面
纹理是在Photoshop中制作的,终于效果则是在Unity里得到的.这样的类型的材质.在3D游戏中非经常见.
- ipython notebook 如何打开.ipynb文件?
标签: pythontensorflow 2017-03-29 14:17 235人阅读 评论(0) 收藏 举报 分类: TensorFlow(13) 转自:https://www.zhihu.c ...
- Nginx详细的安装教程(linux)
转:https://blog.csdn.net/u013641234/article/details/73838472 Nginx作为一个web服务器,目前使用最多的就利用其负载均衡,本篇着重讲解的是 ...