C语言发送email

C语言发送email   应用:分布式评测系统中检测到连接断开后向管理员发送邮件。 一、认证方式  ESMTP(ExtensionSMTP)即认证的邮件传输方式,是邮件服务器系统为了限制非本系统的正式用户利用本系统散发垃圾邮件或其他不当行为而开设的一项安全认证服务。它与传统的SMTP方式相比,主要的不同有两点:  1)支持8-bitMIME格式的编码。  2)支持用户身份的验证。  多了一道用

大家好,又见面了,我是你们的朋友全栈君。

    应用:分布式评测系统中检测到连接断开后向管理员发送邮件。

 

一、 认证方式

  ESMTP(Extension SMTP)即认证的邮件传输方式,是邮件服务器系统为了限制非本系统的正式用户利用本系统散发垃圾邮件或其他不当行
为而开设的一项安全认证服务。它与传统的SMTP方式相比,主要的不同有两点:
  1) 支持8-bit MIME格式的编码。
  2) 支持用户身份的验证。
  多了一道用户身份的验证手续,验证之后的邮件发送过程与传统的SMTP方式一致。为了方便用户的使用,绝大多数的ESMTP服务器都继承了
POP3服务器的帐号和密码设置体系,也就是说收发邮件都用同一个帐号和密码。

  根据[RFC 2554]规范,SMTP的认证功能主要是增加了AUTH命令。AUTH命令有多种用法,而且有多种认证机制。AUTH支持的认证机制主要有LOGIN,CRAM-MD5[注1]等。LOGIN应该是大多数免费邮件服务器都支持的,网易与新浪都支持。下面主要针对LOGIN方式进行介绍,其它方式请根据相应的RFC 规范进行修改。
     几乎所有的ESMTP服务器都继承了POP3服务器的账号和密码设置体系,也就是说收发邮件用相同的账号和密码。当然,也可以用不同的账号和密码,但那样无论是电子邮件服务提供商的维护还是用户的使用都会很麻烦,故而很少采用。

LOGIN 方式口令-应答过程如下(S:表示服务器返回,C:表示客户端发送)
  1. C: AUTH LOGIN
  2. S: 334 dXNlcm5hbWU6      // dXNlcm5hbWU6是username:的BASE64编码
  3. C: dXNlcm5hbWU6
  4. S: 334 cGFzc3dvcmQ6     // cGFzc3dvcmQ6是password:的BASE64编码
  5. C: cGFzc3dvcmQ6
  6. S: 235 Authentication successful.
  (1). 为客户端向服务器发送认证指令。
  (2). 服务端返回base64编码串,成功码为334。编码字符串解码后为”username:”,说明要求客户端发送用户名。
  (3). 客户端发送用base64编码的用户名,此处为”username:”。
  (4). 服务端返回base64编码串,成功码为334。编码字符串解码后为”password:”,说明要求客户端发送用户口令。
  (5). 客户端发送用base64编码的口令,此处为”password:”。
  (6). 成功后,服务端返回码为235,表示认证成功可以发送邮件了

二:BASE64编码原理

  Base64编码其实是将3个8位字节转换为4个6位字节,( 3*8 = 4*6 = 24 ) 这4个六位字节 其实仍然是8位,只不过高两位被设置为0. 当一个字
节只有6位有效时,它的取值空间为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代替
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编码的字节,同理,应该补上一个等号。

 

三、发送步骤

1)获得邮件服务器的地址。调用gethostbyname(),将smtp.sina.com作为参数传入,保存返回的 hostent结构的地址,用它的h_addr_list[0]来初始化sockaddr_in结构的sin_addr.S_un.S_addr成员,端口写成25,这是邮件服务标准端口。

 

2)TCP Socket连接。

 

3)使用SMTP来通信了。该通信是个同步的过程,遵守一发一收的规则,连接上后先接收服务器的反馈信息,然后发送“HELO [信息]/r/n”表明身份,命令EHLO和后面的信息要有空格,信息可以什么信息都不加,接收后继续发送“AUTH LOGIN/r/n”,接收后发送用户名(即邮箱地址中@前边的部分),再发送密码,此时服务器返回是否验证成功的信息,若成功则返回代码为235的信息,否则返回535,注意有可能由于服务器的繁忙而导致验证失败,并不是用户名和密码的问题,所以失败后要继续从头开始,连接-发送-接收-验证,另外,用户名和密码采用base64编码。
       验证后就可以发送具体的邮件信息了。首先发送发件人,“MAIL FROM: <用户名@邮件服务器>/r/n”。其次发送收件人,这个可是要起作用的,发送 “RCPT TO: <目的邮箱>”,要发送给几个人,就发送几个“RCPT TO: <目的邮箱>”,然后发送“DATA/r/n”表示要发送具体数据了,数据格式为:邮件头+邮件体
       邮件头:
       From: “想要显示的发件人”<想要显示的邮箱名>/r/n
       To: <想要显示的收件人邮箱地址>/r/n
       Subject: 主题名/r/n/r/n  此处的两个/r/n表示邮件头结束
       邮件体:
       邮件内容
       结束标志为/r/n./r/n
       将这些信息组成一个字符串发送出去就可以了,最后发送“QUIT /r/n”断开连接。
      至此,邮件发送程序便编写完成了。

4)断开TCP连接。

 

四、关键代码

void sendemail(char *mailsrv, char *mailfrom, char *mailto, char *body)
{

    int sockfd = 0,i=0;
    struct sockaddr_in their_addr = {0};
    char buf[1500] = {0};
    char rbuf[1500] = {0};
    char login[128] = {0};
    char pass[128] = {0};

    struct hostent *hp = gethostbyname(mailsrv);
       
    memset(&their_addr, 0, sizeof(their_addr));
    their_addr.sin_family = AF_INET;
    their_addr.sin_port = htons(25);
    their_addr.sin_addr.s_addr = *(int*)(*hp->h_addr_list);

    sockfd = open_socket((struct sockaddr *)&their_addr);
    memset(rbuf,0,1500);
    while(recv(sockfd, rbuf, 1500, 0) == 0)
    {

        printf(“reconnect…/n”);
        sleep(2);
        close(sockfd);
        sockfd = open_socket((struct sockaddr *)&their_addr);
        memset(rbuf,0,1500);
    }
    printf(“%d.%s/n”,i++, rbuf);
   
    //1.EHLO
    memset(buf, 0, 1500);
    sprintf(buf, “EHLO caoli/r/n”);
    send(sockfd, buf, strlen(buf), 0);
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    printf(“%d.%s/n”,i++, rbuf);
    //2.AUTH LOGIN
    memset(buf, 0, 1500);
    sprintf(buf, “AUTH LOGIN/r/n”);
    send(sockfd, buf, strlen(buf), 0);
    printf(“%s/n”, buf);
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    printf(“%d.%s/n”,i++, rbuf);
    //3.USER
    memset(buf, 0, 1500);
    sprintf(buf,”caoli”);
    memset(login, 0, 128);
    base64(login, buf, strlen(buf));
    sprintf(buf, “%s/r/n”, login);
    send(sockfd, buf, strlen(buf), 0);
    printf(“%s/n”, buf);
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    printf(“%d.%s/n”,i++, rbuf);
    //4.PASSWD
    sprintf(buf, “33060808”);
    memset(pass, 0, 128);
    base64(pass, buf, strlen(buf));
    sprintf(buf, “%s/r/n”, pass);
    send(sockfd, buf, strlen(buf), 0);
    printf(“%s/n”, buf);
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    printf(“%d.%s/n”,i++, rbuf);
    //5.MAIL FROM
    memset(buf, 0, 1500);
    sprintf(buf, “MAIL FROM:<%s>/r/n”,mailfrom);
    send(sockfd, buf, strlen(buf), 0);
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    printf(“%d.%s/n”,i++, rbuf);
    //6.MAIL TO …(multiple destination)
    sprintf(buf, “RCPT TO:<%s>/r/n”, mailto);
    send(sockfd, buf, strlen(buf), 0);
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    printf(“%d:%d.%s/n”,__LINE__,i++, rbuf);
/*
    sprintf(buf, “RCPT TO:starryheavens@hotmail.com/r/n”);
    send(sockfd, buf, strlen(buf), 0);
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    printf(“%d.%s/n”,i++, rbuf);
*/
    //7.DATA
    sprintf(buf, “DATA/r/n”);
    send(sockfd, buf, strlen(buf), 0);
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    printf(“%d.%s/n”,i++, rbuf);
    //8.CONTENT
    sprintf(buf, “%s/r/n./r/n”, body);
    send(sockfd, buf, strlen(buf), 0);
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    printf(“%d.%s/n”,i++, rbuf);
    //9.QUIT
    sprintf(buf, “QUIT/r/n”);
    send(sockfd, buf, strlen(buf), 0);
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    printf(“%d.%s/n”,i++, rbuf);

    close(sockfd);
    return;
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/131877.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Android开发之AOP编程

    Android开发之AOP编程

  • 什么叫做解析几何_笛卡尔心形函数

    什么叫做解析几何_笛卡尔心形函数解析几何是进行科学研究的重要的数学工具。比如说,要确定船只在大海中航行的位置,就要确立经纬度,这就需要精确的掌握夭体运行的规律;要改善枪炮的性能,就要精确地掌握抛射物体的运行规律。解决这些问题必须采用解析几何。因为它可以利用字母表示流动坐标,用方程刻划一般平面的曲线。解析几何的发明人就是伟大的数学家笛卡尔。笛卡尔15%年出生在法国,父亲是一位相当富有的律师。8岁时,父亲把他送进荃督教会学校读书。他…

    2022年10月10日
  • Red Flag linux硬盘安装

    Red Flag linux硬盘安装 很早以前就想安装linux实验一下,今天从中科红旗RedFlag的网站下载了一个系统安装盘的iso,安装盘一共2CD,这里提前说一下,也不知道是不是我的WinXP文件关联有问题,下载下来的ISO显示的是WinRAR的图标,于是没看扩展名直接解压缩出来了(后面因为这个吃了不少苦头,没办法,习惯了),然后上网站上查了查,网上大都写的不明白,而且重复的很多(是不是高手都用linux,觉得

  • RabbitMQ(七):常用方法说明 与 学习小结

    RabbitMQ(七):常用方法说明 与 学习小结

  • docker部署vue项目_docker部署java

    docker部署vue项目_docker部署java第一步:vue项目打包成dist。npmrunbuild第二步:构建Dockerfile#设置基础镜像,这里使用最新的nginx镜像,前面已经拉取过了FROMnginx#将dist文件中的内容复制到/usr/share/nginx/html/这个目录下面COPYdist//usr/share/nginx/html/第三步:安装nginxdockerpullnginxdockerrun–namenginx-d-p4030:8.

    2022年10月19日
  • vue判断字符串是否含有另一个字符串_js中判断是否包含某个字符串

    vue判断字符串是否含有另一个字符串_js中判断是否包含某个字符串String对象的方法1.indexOf()indexOf()方法可返回某个指定的字符串值在字符串中首次出现的位置。如果要检索的字符串值没有出现,则该方法返回-1。varstr=’你好啊双11!’;console.log(str.indexOf(‘!’)!=-1)//true2.search()search()方法用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号