近段时间,实验室电脑的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++发邮件的更多相关文章

  1. # PHP - 使用PHPMailer发邮件

    PHPMailer支持多种邮件发送方式,使用起来非常简单 1.下载PHPMailer https://github.com/PHPMailer/PHPMailer,下载完成加压后, 把下边的两个文件复 ...

  2. Linux发邮件之mail命令

    一.mail命令 1.配置 vim /etc/mail.rc 文件尾增加以下内容 set from=1968089885@qq.com smtp="smtp.qq.com" set ...

  3. 测试MailUtils,作用是发邮件

    package cn.itcast.test; import java.io.IOException; import javax.mail.MessagingException; import jav ...

  4. SQL Server定时自动抓取耗时SQL并归档数据发邮件脚本分享

    SQL Server定时自动抓取耗时SQL并归档数据发邮件脚本分享 第一步建库和建表 USE [master] GO CREATE DATABASE [MonitorElapsedHighSQL] G ...

  5. 学习linux之用mail命令发邮件

    背景 这两天工作比较闲,网上各种冲浪(这个词暴露我的网龄了).看到一位大神的文章更闲 <>.端详一番,原来是用R语言拼接字符串后用shell命令发出去.发现shell命令既然还能直接发邮件 ...

  6. linux mail利用外部邮箱地址发邮件

    mail命令发送邮件需要sendmail或postfix服务 三种常用格式发信 mail -s "标题" xxx@xxx.xxx #第一种方法,你可以把当前shell当成编辑器来用 ...

  7. 打电话,发短信,发邮件,app跳转

    1.打电话 - (IBAction)callPhone1:(id)sender { NSURL *url = [NSURL URLWithString:@"tel://18500441739 ...

  8. iOS中如何切换到发短信、打电话、发邮件

    我们在做APP的时候,难免会遇到需要调用短信,电话等程序的时候.如美团. 当然,这些都只是一些简单的方法就可以实现,但是时间久了也会淡忘,所以想写这边博客.一是为了再捡起来复习一下,另一个相当于留个备 ...

  9. 发邮件 和 excel导出中文文件名

    /** * 发邮件 * @param email * @param subject * @param body * @throws UnsupportedEncodingException */ pu ...

  10. 【知识积累】JavaMail实现发邮件功能

    一.前言 今天闲来没事,想着通过程序来给别人发邮件.于是,上网搜了一下,相应的资料也很多,刚开始完成了邮件的简单发送,后来想如何能发送附件,继续寻找 答案,但是遇到了一个问题是当我使用txt类型作为附 ...

随机推荐

  1. java性能监控工具jstat-windows

    jstat Monitors Java Virtual Machine (JVM) statistics. This command is experimental and unsupported. ...

  2. react 获取 input 的值

    1.通过 onChange -- e.target.value class App extends Component { state = { username: '张三' }; // 用户名 get ...

  3. Python中的列表、元祖、字典

    一.列表 一组有序项目的集合.可变的数据类型[可进行增删改查] 列表是以方括号"[]"包围的数据集合,不同成员以","分隔. 列表中能够包括不论什么数据类型,也 ...

  4. sonar + ieda实现提交代码前代码校验

    代码风格不同一直是一件停头疼的事情,因为不同的工作经验,工作经历,每个人的代码风格不尽相同,造成一些代码在后期的维护当中难以维护, 查阅一些资料之后发现 idea + sonar 的方式比较适合我,实 ...

  5. python(28)- 面向对象练习Ⅱ

    题目一:总结 1.什么是绑定到对象的方法,如何定义,如何调用,给谁用?有什么特性? 类内定义的函数,不经装饰器装饰,被实例化对象调用,会默认传入一个self参数,对象将会传递给self: 定义方式比较 ...

  6. nightwatch testing 注意事项

    coding style 好的測試項目應該盡量不要使用pause 並且要有驗證的機制 .click('input.btn') //.pause(3000) .waitForElementVisible ...

  7. nodejs REPL(交互式解释器)

    Node.js REPL(交互式解释器) Node.js REPL(Read Eval Print Loop:交互式解释器) 表示一个电脑的环境,类似 Window 系统的终端或 Unix/Linux ...

  8. UVA 11888 - Abnormal 89&#39;s(Manachar)

    UVA 11888 - Abnormal 89's option=com_onlinejudge&Itemid=8&page=show_problem&category=524 ...

  9. 谈谈加载(Loading)的那点事

    谈谈加载(Loading)的那点事 2013/10/12 | 分类: 设计 | 0 条评论 | 标签: 交互设计, 加载 分享到:33 原文出处: 搜狐焦点 对于加载(loading),想必大家都不陌 ...

  10. C# wince 实现软件忙鼠标状态改变

    eg: Cursor.Current = Cursors.WaitCursor; dosomething(); Cursor.Current = Cursors.Default; Cursor.Cur ...