上一章写了socket 操作,这一章用上一章的内容写smtp协议相关操作的函数。
首先是smtp.h文件
#ifndef SMTP_H
#define SMTP_H
#include"renyj_sock.h"
//根据smtp协议,用来处理发送和接收EHLO的函数
int mail_say_hello(char *hello_domain);
//用来处理FROM命令和接受其回复的函数
int mail_from(char *from);
//用来处理RCPT TO命令和接收其回复的函数
int mail_to(char *to);
//用来处理DATA 命令和接收其回复的函数
int mail_data();
//用来处理QUIT命令和接收其回复的函数
int mail_quit();
//用来处理发送 . 和接收其回复的函数
int mail_eom();
//用来处理用户认证的函数
int mail_auth(char *uer,char *pass);
//用来发送邮件的函数
int send_the_mail(char *from,char *to,char *server,int port,char *user,
char *pass,char *subject,char *msgline,int timeout);
#endif
二、函数实现,smtp.c文件。
#include"smtp.h"
#include"mutils.h"
char mail_buff[1000] = "";
//用来读取邮件服务器回复的函数
int smtp_read_line()
{
memset(mail_buff,0x00,sizeof(mail_buff));
int rc = mysock_gets(mail_buff,100,10);
if (rc < 0)
{
return rc;
}
debug("[S] -----> %s",mail_buff);
return rc;
}
/*处理EHLO函数,这里我发现需要向服务器发送两次EHLO命令,可能时跟服务器有关系。如果有清楚的大神还请指点一下。我这样写是根据实际情况自己分析出来的。*/
int mail_say_hello(char *hello_domain)
{
memset(mail_buff,0x00,sizeof(mail_buff));
mysock_puts("EHLO ");
int rc = smtp_read_line();
sprintf(mail_buff,"EHLO %s\r\n",hello_domain);
mysock_puts(mail_buff);
do
{
rc = smtp_read_line();
if (rc < 0)
{
debug("say hello error");
return -1;
}
}while(NULL != strstr(mail_buff,"-"));
}
//处理FROM命令
int mail_from(char *from)
{
memset(mail_buff,0x00,sizeof(mail_buff));
sprintf(mail_buff,"MAIL FROM: <%s>\r\n",from);
mysock_puts(mail_buff);
memset(mail_buff,0x00,sizeof(mail_buff));
int rc = smtp_read_line();
if (rc<0)
{
debug("rcv mail from error");
return -1;
}
}
//处理TO命令
int mail_to(char *to)
{
memset(mail_buff,0x00,sizeof(mail_buff));
sprintf(mail_buff,"RCPT TO: <%s>\r\n",to);
mysock_puts(mail_buff);
memset(mail_buff,0x00,sizeof(mail_buff));
int rc = smtp_read_line();
if (rc<0)
{
debug("rcv mail to error");
return -1;
}
}
//处理DATA命令。
int mail_data()
{
memset(mail_buff,0x00,sizeof(mail_buff));
mysock_puts("DATA\r\n");
int rc = smtp_read_line();
if (rc < 0)
{
debug("rcv data error");
return -1;
}
}
//发送 . 来让邮件结束输入
int mail_eom()
{
mysock_puts("\r\n.\r\n");
smtp_read_line();
}
//退出邮件
int mail_quit()
{
mysock_puts("QUIT\r\n");
smtp_read_line();
}
//邮件的认证
int mail_auth(char *user,char *pass)
{
char *b64 = NULL;
char buf[1000]="";
//发送LOGIN认证,因为是针对qq服务器,我知道它支持这个。
mysock_puts("AUTH LOGIN\r\n");
int rc = smtp_read_line();
if (rc < 0)
{
debug("auth login rcv error");
return -1;
}
memset(mail_buff,0x00,sizeof(mail_buff));
//这里需要对用户名进行base64的加密。不一定非要用这个函数,如果有人要用,我会上传源码
b64=mutils_encode_base64_noformat(user,strlen(user));
if (b64 == NULL)
{
debug("Could not base64 encode user: %s",user);
return -1;
}
memset(buf,0,sizeof(buf));
(void) snprintf(buf,sizeof(buf)-1,"%s\r\n",b64);
mysock_puts(buf);
memset(mail_buff,0x00,sizeof(mail_buff));
rc = smtp_read_line();
if (rc < 0)
{
debug("user error");
return -1;
}
//这里需要对用户名进行base64的加密
b64=mutils_encode_base64_noformat(pass,strlen(pass));
if (b64 == NULL)
{
debug("Could not base64 encode passworf of user: %s",pass);
return -1;
}
memset(buf,0,sizeof(buf));
(void) snprintf(buf,sizeof(buf)-1,"%s\r\n",b64);
mysock_puts(buf);
memset(mail_buff,0x00,sizeof(mail_buff));
rc = smtp_read_line();
if (rc < -1)
{
debug("pass error");
return -1;
}
}
int send_the_mail(char *from,char *to,char *server,int port,char *user,
char *pass,char *subject,char *msgline,int timeout)
{
//init the client socket
int rc;
rc = myclient_sock(0,server,port,timeout);
if (rc < 0)
{
debug("myclient_sock error");
return -1;
}
set_socket(rc);
//turn on the ssl
char *cip = NULL;
openssl_init(cip);
turn_on_ssl(get_socket());
//say ehlo
char *hello_domain = "localhost";
mail_say_hello(hello_domain);
//use login,and start AUTH
debug("start AUTH");
mail_auth(user,pass);
//FROM
debug("start FROM");
mail_from(from);
//TO
debug("start TO");
mail_to(to);
//DATA
debug("start DATA");
mail_data();
//send the Subject
char subjectbuff[150] = "";
//这里就是标题内容
sprintf(subjectbuff,"Subject: %s\r\n",subject);
//from可能必须按照你登录的账号填写,要不然就会被当做垃圾邮件
mysock_puts("From: xxxxxx@qq.com\r\n");
mysock_puts("Date:\r\n");
mysock_puts("To: xxxxxx@qq.com\r\n");
mysock_puts(subjectbuff);
//这里content-type必须写,要不然发出去的就不知道什么类型了,也不会吧你发的那句话当做消息。
mysock_puts("Content-type: text/plain\r\n\r\n");
mysock_puts(msgline);
//use . end data
debug("start eom");
mail_eom();
//quit the msg
debug("QUIT");
mail_quit();
mysock_close();
return 0;
}