#Linux C语言使用SMTP协议发送邮件(使用25端口)
本程序使用SMTP协议发送邮件,使用普通的25端口,属于非加密邮件。
经测试,可以使用的邮箱服务器有126,163,sohu,QQ企业邮箱等,在使用的时候,有些邮箱可以直接使用密码登录,有些邮件要使用授权码,这个可以看邮箱说明。
返回值:0代表发送邮件成功,<0发送失败。
注意:大部分云服务器禁用了25端口,会导致连接邮箱服务器失败,不是本程序的问题,这种情况需要使用465端口SSL加密方式发邮件,SSL方式发送邮件后面再写。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct Base64Date6
{
unsigned int d4:6;
unsigned int d3:6;
unsigned int d2:6;
unsigned int d1:6;
};
char ConvertToBase64(char uc)
{
if(uc < 26)
return 'A' + uc;
if(uc < 52)
return 'a' + (uc - 26);
if(uc < 62)
return '0' + (uc - 52);
if(uc == 62)
return '+';
return '/';
}
void EncodeBase64(char*dbuf,char*buf128,int len)
{
struct Base64Date6*ddd =NULL;
int i = 0;
char buf[256] = {0};
char *tmp = NULL;
char cc = '\0';
memset(buf, 0, 256);
strcpy(buf, buf128);
for(i = 1; i <= len / 3; i++)
{
tmp = buf + (i - 1) * 3;
cc = tmp[2];
tmp[2] = tmp[0];
tmp[0] = cc;
ddd = (struct Base64Date6*)tmp;
dbuf[(i - 1) * 4 + 0]=ConvertToBase64((unsigned int)ddd->d1);
dbuf[(i - 1) * 4 + 1]=ConvertToBase64((unsigned int)ddd->d2);
dbuf[(i - 1) * 4 + 2]=ConvertToBase64((unsigned int)ddd->d3);
dbuf[(i - 1) * 4 + 3]=ConvertToBase64((unsigned int)ddd->d4);
}
if(len % 3 == 1)
{
tmp = buf + (i - 1) * 3;
cc = tmp[2];
tmp[2] = tmp[0];
tmp[0] = cc;
ddd = (struct Base64Date6*)tmp;
dbuf[(i - 1) * 4 + 0]=ConvertToBase64((unsigned int)ddd->d1);
dbuf[(i - 1) * 4 + 1]=ConvertToBase64((unsigned int)ddd->d2);
dbuf[(i - 1) * 4 + 2]='=';
dbuf[(i - 1) * 4 + 3]='=';
}
if(len % 3 == 2)
{
tmp = buf + ( i - 1) * 3;
cc = tmp[2];
tmp[2] = tmp[0];
tmp[0] = cc;
ddd = (struct Base64Date6*)tmp;
dbuf[(i - 1) * 4 + 0]=ConvertToBase64((unsigned int)ddd->d1);
dbuf[(i - 1) * 4 + 1]=ConvertToBase64((unsigned int)ddd->d2);
dbuf[(i - 1) * 4 + 2]=ConvertToBase64((unsigned int)ddd->d3);
dbuf[(i - 1) * 4 + 3]='=';
}
return;
}
class Socket_RAII{
public:
Socket_RAII(int sockfd)
{
m_sockfd = sockfd;
}
~Socket_RAII()
{
close(m_sockfd);
}
private:
int m_sockfd;
};
int SendEmail(
const char *smtp,//邮箱服务器地址:如smtp.exmail.qq.com
unsigned short port,//邮箱服务器商品:25
const char *account,//发送方的邮箱帐号
const char *password,//发送方的邮箱密码或授权码
const char* email,//目标邮箱
const char* body,//邮件正文件内容,字符串
const char* from_name,//邮件发送方的名称
const char* to_name,//邮件接收方的名称
const char* subject )//邮件主题
{
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
hostent* hptr = gethostbyname(smtp);
server_addr.sin_addr = *(struct in_addr*)*hptr->h_addr_list;
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
int ret = connect(sockfd, (struct sockaddr*)(&server_addr), sizeof(server_addr));
if(ret == -1)
{
printf("%s():connect email server failed:%s(errno:%d)\n",
__func__, strerror(errno), errno);
return -1;
}
Socket_RAII Raii(sockfd); //使用RAII关闭SOCKET连接
char rbuf[255];
memset(rbuf, 0, sizeof(rbuf));
ret = recv(sockfd, rbuf, sizeof(rbuf), 0);
if(ret <= 0)
return -2;
if(strncmp(rbuf, "220", 3) != 0)
return -3;
char sbuf[1500];
// EHLO
int len = snprintf(sbuf, sizeof(sbuf), "EHLO HYL-PC\r\n");
ret = send(sockfd, sbuf, len, 0);
if(ret == SOCKET_ERROR)
return -4;
memset(rbuf, 0, sizeof(rbuf));
ret = recv(sockfd, rbuf, sizeof(rbuf), 0);
if(ret <= 0)
return -5;
if(strncmp(rbuf, "250", 3) != 0)
return -6;
// AUTH LOGIN
len = snprintf(sbuf, sizeof(sbuf), "AUTH LOGIN\r\n");
ret = send(sockfd, sbuf, len, 0);
if(ret == SOCKET_ERROR)
return -7;
memset(rbuf, 0, sizeof(rbuf));
ret = recv(sockfd, rbuf, sizeof(rbuf), 0);
if(ret <= 0)
return -8;
if(strncmp(rbuf, "334", 3) != 0)
return -9;
//USER
len = snprintf(sbuf, sizeof(sbuf), "%s", account);
char login[128];
memset(login, 0, sizeof(login));
EncodeBase64(login, sbuf, len);
len = snprintf(sbuf, sizeof(sbuf), "%s\r\n", login);
ret = send(sockfd, sbuf, len, 0);
if(ret == SOCKET_ERROR)
return -10;
memset(rbuf, 0, sizeof(rbuf));
ret = recv(sockfd, rbuf, sizeof(rbuf), 0);
if(ret <= 0)
return -11;
if(strncmp(rbuf, "334", 3) != 0)
return -12;
//PASSWORD
len = snprintf(sbuf, sizeof(sbuf), "%s", password);
//char login[128];
memset(login, 0, sizeof(login));
EncodeBase64(login, sbuf, len);
len = snprintf(sbuf, sizeof(sbuf), "%s\r\n", login);
ret = send(sockfd, sbuf, len, 0);
if(ret == SOCKET_ERROR)
return -13;
memset(rbuf, 0, sizeof(rbuf));
ret = recv(sockfd, rbuf, sizeof(rbuf), 0);
if(ret <= 0)
return -14;
if(strncmp(rbuf, "235", 3) != 0)
return -15;
// MAIL FROM
len = snprintf(sbuf, sizeof(sbuf), "MAIL FROM:<%s>\r\n", account);
ret = send(sockfd, sbuf, len, 0);
if(ret == SOCKET_ERROR)
return -16;
memset(rbuf, 0, sizeof(rbuf));
ret = recv(sockfd, rbuf, sizeof(rbuf), 0);
if(ret <= 0)
return -17;
if(strncmp(rbuf, "250", 3) != 0)
return -18;
// RCPT TO
len = snprintf(sbuf, sizeof(sbuf), "RCPT TO:<%s>\r\n", email);
ret = send(sockfd, sbuf, len, 0);
if(ret == SOCKET_ERROR)
return -19;
memset(rbuf, 0, sizeof(rbuf));
ret = recv(sockfd, rbuf, sizeof(rbuf), 0);
if(ret <= 0)
return -20;
if(strncmp(rbuf, "250", 3) != 0)
return -21;
// DATA 准备开始发送邮件内容
len = snprintf(sbuf, sizeof(sbuf), "DATA\r\n");
ret = send(sockfd, sbuf, len, 0);
if(ret == SOCKET_ERROR)
return -22;
memset(rbuf, 0, sizeof(rbuf));
ret = recv(sockfd, rbuf, sizeof(rbuf), 0);
if(ret <= 0)
return -23;
if(strncmp(rbuf, "354", 3) != 0)
return -24;
// 发送邮件内容,\r\n.\r\n内容结束标记
len = snprintf(sbuf, sizeof(sbuf),
"From: %s<%s>\r\n""To: %s<%s>\r\n""Subject: %s\r\n\r\n""%s\r\n.\r\n",
from_name, account, to_name, email, subject, body);
ret = send(sockfd, sbuf, len, 0);
if(ret == SOCKET_ERROR)
return -25;
memset(rbuf, 0, sizeof(rbuf));
ret = recv(sockfd, rbuf, sizeof(rbuf), 0);
if(ret <= 0)
return -26;
if(strncmp(rbuf, "250", 3) != 0)
return -27;
// QUIT
len = snprintf(sbuf, sizeof(sbuf), "QUIT\r\n");
ret = send(sockfd, sbuf, len, 0);
if(ret == SOCKET_ERROR)
return -28;
memset(rbuf, 0, sizeof(rbuf));
ret = recv(sockfd, rbuf, sizeof(rbuf), 0);
if(ret <= 0)
return -29;
if(strncmp(rbuf, "221", 3) != 0)
return -30;
return 0;
};
int main(int argc, char* argv[])
{
int ret = SendEmail("smtp.exmail.qq.com", 25, "account","password",
"[email protected]", "This is the body", "from name",
"To name", "This is the subject");
if(ret == 0)
printf("SendEmail success\n");
else
printf("SendEmail failed,errno= %d\n",ret);
return 0;
}