用SMTP发送邮件

一、
假设由发件人jmst66(jmst66@163.com)发到neuwjyou@sina.com邮箱,以下主机返回的命令都表示命令成功时返回的命令。发送过程如下:

1.连接主机smtp.163.com
主机返回:220 163.com Anti-spam GT for Coremail System (163com[20050206])

2.第一次会话
发送命令:EHLO mailto:jmst66@163.com%20r%20n (说明:发送的命令后都有换行标识"/r/n")
返回数据:
250-mail
250-PIPELINING
250-AUTH LOGIN PLAIN
250-AUTH=LOGIN PLAIN
250 8BITMIME

3.用户登录
发送命令:AUTH LOGIN/r/n
返回数据:334 dXNlcm5hbWU6 (说明:这是username的base64编码)
发送帐号:am1zdDY2(这是jmst66的base64编码)

返回数据:334 UGFzc3dvcmQ6 (说明:这是password的base64编码)
发送密码:xxxxxxx(这里是jmst66这个帐号的密码的base64编码)

返回数据:235 Authentication successful (登录成功)

4:发送邮箱说明
发送命令:MAIL FROM:<mailto:jmst66@163.com>%20r%20n
返回数据:250 Mail OK

5.目的邮箱说明
发送命令:RCPT TO: <mailto:neuwjyou@sina.com>%20r%20n
返回数据:250 Mail OK

6.请求发送邮件
发送命令:DATA/r/n
返回命令:354 End data with <CR><LF>.<CR><LF>

7.发送邮件头和邮件体
发送数据:直接是完整的数据以“<CR><LF>.<CR><LF>”结束
返回数据:250 Mail OK queued as smtp1,wKjRC7D7f6MFoOdGa_i7MA==.52140S2 1189584903

8.结束发送数据
发送命令:QUIT/r/n
接收数据:221 Bye

9.断开连接


二、
具体程序实现简要说明如下:
1.连接主机smtp.163.com

sockaddr_in serverAddr;
SOCKET sock;
hostent * host;
host = gethostbyname(serverHostName.c_str());
if(host==NULL){
return -1;
}

sock = socket(AF_INET, SOCK_STREAM,0);
serverAddr.sin_addr = *(struct in_addr*)host->h_addr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(serverPort);

if(connect(sock,(const sockaddr*)&serverAddr,sizeof(sockaddr))==SOCKET_ERROR)
{
closesocket(sock);
return -1;
}

//加一个判断主机返回的数据是否表示成功
DEAL_RETURN_CODE(GetResponseCode(sock,220,str));


2.第一次会话
char buffer[BUFFER_SIZE];
sprintf(buffer,"EHLO %s/r/n",from);//from为char数据。存储发送地址
send(sock,buffer,strlen(buffer),0);

3.用户登录
sprintf(buffer,"AUTH LOGIN/r/n");
send(sock,buffer,strlen(buffer),0);

//USER NAME
//User name is coded by base64.
EncodingBase64(username.c_str(),buffer);//先将用户帐号经过base64编码
strcat(buffer,"/r/n");
send(sock,buffer,strlen(buffer),0);

//password coded by base64
EncodingBase64(pass.c_str(),buffer);//先将密码经过base64编码
strcat(buffer,"/r/n");
send(sock,buffer,strlen(buffer),0);


4:发送邮箱说明
sprintf(buffer,"MAIL FROM:<%s>/r/n",from.c_str());
send(sock,buffer,strlen(buffer),0);


5.目的邮箱说明
sprintf(buffer,"RCPT TO: <%s>/r/n",to.c_str());
send(sock,buffer,strlen(buffer),0);
DEAL_RETURN_CODE(GetResponseCode(sock,250,str));


6.请求发送邮件
sprintf(buffer,"DATA/r/n");
send(sock,buffer,strlen(buffer),0);
DEAL_RETURN_CODE(GetResponseCode(sock,354,str));

7.发送邮件头和邮件体,发送邮件的主题部分应该先将其格式化处理之后再发送,这里就不说明格式话的程序了。
//DATA head
send(sock,mailHead,strlen(mailHead),0);

//DATA body
send(sock,mailBody,strlen(mailBody),0);


8.结束发送数据
strcpy(buffer,"QUIT/r/n");
send(sock,buffer,strlen(buffer),0);
DEAL_RETURN_CODE(GetResponseCode(sock,221,str));

9.断开连接
closesocket(sock);


}

邮件头,由
Date:
From:
To:
Subject:
Message-ID:
X-mailer:
Mime-Version:

如下是一封邮件经过编码后的数据:

Date:Wed, 12 Sep 2007 16:13:56 +0800
From: <jmst66@163.com>
To: <zzzheng@hit.edu.cn>
Subject: =?gb2312?B?Sk1TVCC52NPat6Kx7c7E1cK78b2xtfey6Q==?=
Message-ID: <1189584836@163.com>
X-mailer: =?GB2312?B?19S8urXETWFpbGVy?=
Mime-Version: 1.0
Content-Type: multipart/alternative;
???????? boundary="====MajorSplitTag===="
This is a multi-part message in MIME format.

--====MajorSplitTag====
Content-Type: text/plain;
???????? charset="gb2312"
Content-Transfer-Encoding: base64


--====MajorSplitTag====
Content-Type: text/html;
???????? charset="gb2312"
Content-Transfer-Encoding: base64

PGh0bWw+DQo8aGVhZD4NCjxtZXRhIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIgY29udGVudD0idGV4
dC9odG1sOyBjaGFyc2V0PWdiMjMxMiIgLz4NCjx0aXRsZT7O3rHqzOLOxLW1PC90aXRsZT4NCjwvaGVh
ZD4NCg0KPGJvZHk+DQo8Zm9udCBzaXplPSIrMSI+DQo8cCBhbGlnbj0ibGVmdCI+1/C+tLXE1/fV36Os
xPq6w6O6IDwvcD4NCjxwIGFsaWduPSJsZWZ0Ij4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDvS8s7Sv6/S
qsrVvK/E+tTaobZKTVNUobe3orHtwtvOxLXEz+C52NDFz6KjrMbk1tCw/MCou/G9scfpv/ajrM7E1cKx
u9L908O1xLTOyv26zbG70v3Tw7XEv6/O78P7s8ajrLvy1d+78deowPvJ6sfrtcTWpMrpoaPH68T6vavL
+beise3OxNXCtcTM4sS/o6zIq7K/1/fV36Ost6Kx7bXEICDE6qOsvu2jqMbao6mjrNKzILyw0+u45bz+
z+C52LXEu/G9sdakyum78tXf16jA+9akyumjrMmow+i687eiy83WwTx1PkpNU1Q2NkAxNjMuQ29tPC91
Prvy1d+9q8bkuLTTobz+tKvV5tbBIKO6IDAyNKOtODM5NzkyNDihoyA8L3A+DQo8cCBhbGlnbj0ibGVm
dCI+1/fV37XEyNnT/tKyysfO0sPHxtq/r7XEyNnT/qOst8ezo7jQ0LvE+rbUztLDx7mk1/e1xMXkus+j
rNKyz6PN+8T6us3E+rXEzazKwsPHxNzSu8jnvMjN+bXY1qez1s7Sw8ejoSA8L3A+DQo8cCBhbGlnbj0i
bGVmdCI+16PE+qO6ILmk1/fLs8D7o6zN8srCyOfS4qOhIDxiciAvPg0KICC0y9bCIDwvcD4NCjxwIGFs
aWduPSJsZWZ0Ij6+tMDxIDwvcD4NCjxwIGFsaWduPSJsZWZ0Ij5KTVNUseC8rbK/IDwvcD4NCjwvZm9u
dD4NCjxwIGFsaWduPSJsZWZ0Ij4tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0gPGJyIC8+DQogIEpvdXJuYWwgb2YgTWF0ZXJpYWxzICBTY2llbmNlICZhbXA7IFRlY2hu
b2xvZ3kgPC9wPg0KPHAgYWxpZ249ImxlZnQiPjcyIFdlbmh1YSBSb2FkLCBTaGVueWFuZyAxMTAwMTYs
IENoaW5hIDwvcD4NCjxwIGFsaWduPSJsZWZ0Ij5UZWw6IDAyNC04Mzk3ODIwOCwgIEZheDogMDI0LTgz
OTc5MjQ4IDwvcD4NCjxwIGFsaWduPSJsZWZ0Ij5FLW1haWw6IDxhIGhyZWY9Im1haWx0bzpKTVNUQGlt
ci5hYy5jbiI+Sk1TVEBpbXIuYWMuY248L2E+LCA8YSBocmVmPSJtYWlsdG86Sk1TVDY2QDE2My5jb20i
PkpNU1Q2NkAxNjMuY29tPC9hPiA8L3A+DQo8cCBhbGlnbj0ibGVmdCI+V2ViOiA8YSBocmVmPSJodHRw
Oi8vd3d3LkpNU1QuT1JHIj5XV1cuSk1TVC5PUkc8L2E+IDxiciAvPg0KICAtLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gPC9wPg0KPC9ib2R5Pg0KPC9odG1sPg0K
--====MajorSplitTag====

Base64编码其实是将3个8位字节转换为4个6位字节,(?3*8?=?4*6?=?24?)?这4个六位字节?其实仍然是8位,只不过高两位被设置为0.?当一个字节只有6位有效时,它的取值空间为0?到?2的6次方减1?即63,也就是说被转换的Base64编码的每一个编码的取值空间为(0~63)?。?
????
???? 事实上,0~63之间的ASCII码有许多不可见字符,所以应该再做一个映射,映射表为?
????
???? ‘A‘?~?‘Z‘???ASCII(0?~?25)?
????
???? ‘a’?~?‘z‘???ASCII(26?~?51)?
????
???? ‘0’?~?‘9‘???ASCII(52?~?61)?
????
???? ‘+‘???ASCII(62)?
????
???? ‘/‘???ASCII(63)?
????
???? 这样就可以将3个8位字节,转换为4个可见字符。?
????
???? 具体的字节拆分方法为:(图(画得不好,领会精神?:-))?
????
???? aaaaaabb?ccccdddd?eeffffff???//abcdef其实就是1或0,为了看的清楚就用abcdef代替
????
???? ~~~~~~~~?~~~~~~~~?~~~~~~~~?
????
???? 字节?1?字节?2?字节?3?
????
????     ||?
????     //?
????
???? 00aaaaaa?00bbcccc?00ddddee?00ffffff?
????
???? 注:上面的三个字节位原文,下面四个字节为Base64编码,其前两位均为0。?
????
???? 这样拆分的时候,原文的字节数量应该是3的倍数,当这个条件不能满足时,用全零字节?
????
???? 补足,转化时Base64编码用=号代替,这就是为什么有些Base64编码以一个或两个等号结?
????
???? 束的原因,但等号最多有两个,因为:如果F(origin)代表原文的字节数,F(remain)代?
????
???? 表余数,则?
????
???? F(remain)?=?F(origin)?MOD?3?成立。?
????
???? 所以F(remain)的可能取值为0,1,2.?
????
???? 如果设?n?=?[F(origin)?–?F(remain)]?/?3?
????
???? 当F(remain)?=?0?时,恰好转换为4*n个字节的Base64编码。?
????
???? 当F(remain)?=?1?时,由于一个原文字节可以拆分为属于两个Base64编码的字节,为了?
????
???? 让Base64编码是4的倍数,所以应该为补2个等号。?
????
???? 当F(remain)?=?2?时,由于两个原文字节可以拆分为属于3个Base64编码的字节,同理,?
????
???? 应该补上一个等号。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值