近段时间,实验室电脑的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. maven编译maven-surefire-plugin插件报错

    1.编译错误信息: [INFO] ------------------------------------------------------------------------ [ERROR] Fa ...

  2. Hibernate调试——定位查询源头

    本文是我在importNew翻译的文章,首发在importNew,这里会定期更新链接. 为什么有时Hibernate会在程序某一部分生成一条指定sql查询?这个问题让人非常难立马理解.当处理不是我们本 ...

  3. Vue 字面量语法 vs 动态语法

    初学者常犯的一个错误是使用字面量语法传递数值: <!-- 传递了一个字符串 "1" --> <comp some-prop="1">&l ...

  4. [Python-tools]defaultdict的使用场景

    Python标准库中collections对集合类型的数据结构进行了非常多拓展操作.这些操作在我们使用集合的时候会带来非常多的便利.多看看非常有优点. defaultdict是当中一个方法,就是给字典 ...

  5. 无线热点登陆认证原理探究---captive portal

    什么是Captive Portal 大家肯定都连过公共场所的wifi热点,比如麦当劳等地方的.他们的wifi往往一连上去就会弹出一个要求登录或者微信关注之类的页面,只有在这个页面完成操作了才能正常访问 ...

  6. css实现弹出窗体始终垂直水平居中

    <!DOCTYPE html><html> <head> <meta charset=" utf-8"> <meta name ...

  7. Linux 下编译安装OpenCV(zhuanzai)

    http://www.cnblogs.com/emouse/archive/2013/02/22/2922940.html Cmake的安装 OpenCV 2.2以后版本需要使用Cmake生成make ...

  8. 【leetcode】Jump Game I, II 跳跃游戏一和二

    题目: Jump Game I: Given an array of non-negative integers, you are initially positioned at the first ...

  9. 一个兼容性比较好的图片左右滚动的js

    下载地址:http://www.cnblogs.com/RightDear/admin/Files.aspx 文件:shhds.rar

  10. 7-12 畅通工程之最低成本建设问题(30 point(s)) 【PRIME】

    7-12 畅通工程之最低成本建设问题(30 point(s)) 某地区经过对城镇交通状况的调查,得到现有城镇间快速道路的统计数据,并提出"畅通工程"的目标:使整个地区任何两个城镇间 ...