linux下用C编写的基于smtp的邮件发送程序【转】
smtp协议原理:http://blog.csdn.net/woshinia/article/details/8994833
我的webf服务器是动态ip,因此需要检测服务器ip的变化然后更新域名的ip,打算检测到ip变化后自动发送邮件告知自己,于是上网搜了下编程发送邮件的方法,大部分是基于vc的,我找了个例子修改成了linux下的程序。这个程序是基于smtp协议的,smtp是基于tcp的,有兴趣的可以先自己看看smtp协议,这样看程序会更容易理解。
这个程序目前126的邮箱经测试成功发送,新浪的虽然显示发送成功但是总也收不到,有空再慢慢实验吧,其他邮箱还未测试。
程序如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>
#include <netinet/in.h>
#include <limits.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <ctype.h>
// Function prototype
void StreamClient(char *szServer, short nPort, char *szMessage);
// Helper macro for displaying errors
////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{
char hostname[255];
int nRet;
short nPort;
nPort =25;
StreamClient("smtp.126.com", nPort, "AUTH LOGIN\r\n");
return 0;
}
////////////////////////////////////////////////////////////
void StreamClient(char *szServer, short nPort, char *szMessage)
{
int sockfd;
char buffer[1024];
struct sockaddr_in server_addr;
struct hostent *host;
if((host=gethostbyname(szServer))==NULL)/*取得主机IP地址*/
{
fprintf(stderr,"Gethostname error, %s\n", strerror(errno));
exit(1);
}
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)/*建立SOCKET连接*/
{
fprintf(stderr,"Socket Error:%s\a\n",strerror(errno));
exit(1);
}
/* 客户程序填充服务端的资料 */
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(nPort);
server_addr.sin_addr=*((struct in_addr *)host->h_addr);
/* 客户程序发起连接请求 */
if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)/*连接网站*/
{
fprintf(stderr,"Connect Error:%s\a\n",strerror(errno));
exit(1);
}
printf("\nStream Client connecting to server: %s on port: %d",szServer, nPort);
char szBuf[1024];
memset(szBuf,0,1024);
int nRet;
// strcpy(szBuf, "From the Client");
char buf[350]="0";
char server[250];
gethostname(server,250);
strcpy(buf, "HELO ");
strcat(buf, szServer);
strcat(buf, " \r\n");
printf("%s:::%d",buf,strlen(buf));
//
// Wait for a reply
//
nRet = recv(sockfd,szBuf,sizeof(szBuf)+1,0); printf("\nData received OVER DATA: %s", szBuf);
nRet = send(sockfd, buf, strlen(buf), 0);printf("\nsend %s",buf);
nRet = recv(sockfd, szBuf, sizeof(szBuf), 0); printf("\nData received2: %s", szBuf);
//发送准备登陆信息
nRet = send(sockfd, "AUTH LOGIN\r\n", strlen("AUTH LOGIN\r\n"), 0);
nRet = recv(sockfd, szBuf, sizeof(szBuf), 0); printf("\nData received LOGIN: %s", szBuf);
//发送用户名和密码,这里的用户名和密码必须用base64进行转码,发送转码以后的字符串,对于126邮箱来说用户名是@前面的字符串
nRet = send(sockfd,"转码后的用户名\r\n", strlen("转码后的用户名\r\n"),0);printf("\nData Send USERNAME");
nRet = recv(sockfd, szBuf, sizeof(szBuf),0);printf("\nData received USERNAME: %s", szBuf);printf("\nData Send PASS");
//发送用户密码
nRet = send(sockfd,"转码后的密码\r\n", strlen("转码后的密码\r\n"), 0);
//printf("\nData Send PASS");
nRet = recv(sockfd, szBuf, sizeof(szBuf),0); printf("\nData received USERPASSWORD: %s", szBuf);
//发送[发送邮件]的信箱(改成你的邮箱!),该邮箱要与用户名一致,否则发送不成功
send(sockfd,"MAIL FROM: <server_ip_alert@126.com>\r\n",strlen("MAIL FROM: <server_ip_alert@126.com>\r\n"),0);printf("\nsend MAIL FROM\n");
nRet = recv(sockfd, szBuf, sizeof(szBuf), 0);printf("\nData received MAILFROM: %s", szBuf);
//发送[接收邮件]的邮箱
nRet= send(sockfd,"RCPT TO: <tootoogo@hotmail.com>\r\n",strlen("RCPT TO: <tootoogo@hotmail.com>\r\n"),0);printf("\nsend RCPT TO\r\n");
nRet = recv(sockfd, szBuf, sizeof(szBuf), 0); printf("\nData received TO MAIL: %s", szBuf);
/*
nRet= send(sockfd,"RCPT TO: <server_ip_alert@hotmail.com>\r\n",strlen("RCPT TO: <server_ip_alert@hotmail.com>\r\n"),0);printf("\nsend RCPT TO\r\n");
nRet = recv(sockfd, szBuf, sizeof(szBuf), 0); printf("\nData received TO MAIL: %s", szBuf);
*/
char MailData[] ="From: \"server_ip_alert@sina.com\"<server_ip_alert@sina.com>\r\nTo: tootoogo@hotmail.com\r\nSubject: IP Address\r\n\r\n"; //主题可以改成别的
//各诉邮件服务器,准备发送邮件内容
send(sockfd,"DATA\r\n", strlen("DATA\r\n"),0);printf("\nsend DATA\n");
// nRet = recv(sockfd, szBuf, sizeof(szBuf)+1, 0); printf("\nData receivedSEND DATA: %s", szBuf);
//发送邮件标题
send(sockfd,MailData, strlen(MailData),0);
//发送邮件内容
send(sockfd,"test!!!!\r\n", strlen("abcdefg\r\n"),0);//我随便写了几个字符进行测试
//发送邮件结束
send(sockfd,"\r\n.\r\n", strlen("\r\n.\r\n"),0);
//接收邮件服务器返回信息
nRet = recv(sockfd,szBuf,sizeof(szBuf),0); printf("\nData received OVER DATA: %s", szBuf);
send(sockfd,"QUIT\r\n", strlen("QUIT\r\n"),0);
nRet = recv(sockfd,szBuf,sizeof(szBuf),0); printf("\nData received QUIT: %s", szBuf);
//
// Display the received data
//
//printf("\nData received3: %s", szBuf);
close(sockfd);
return;
}
1、安装库libesmtp-devel
yum install libesmtp-devel
或
apt-get install libesmtp-devel
如果没法用命令安装,就上http://www.stafford.uklinux.net/libesmtp/自己下载包安装。
2、不认证即可发信息
#define _XOPEN_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <stdarg.h>
#include <libesmtp.h>
int main() {
smtp_session_t session;
smtp_message_t message;
struct sigaction sa;
const smtp_status_t *status;
char buf[128];
FILE *fp;
/* This program sends only one message at a time. Create an SMTP
session and add a message to it. */
if( (session = smtp_create_session ()) == NULL){
fprintf (stderr, "smtp_create_session problem %s\n",
smtp_strerror (smtp_errno (), buf, sizeof buf));
return 1;
}
if((message = smtp_add_message (session)) == NULL){
fprintf (stderr, "smtp_add_message problem %s\n",
smtp_strerror (smtp_errno (), buf, sizeof buf));
return 1;
}
/* NB. libESMTP sets timeouts as it progresses through the protocol.
In addition the remote server might close its socket on a timeout.
Consequently libESMTP may sometimes try to write to a socket with
no reader. Ignore SIGPIPE, then the program doesn't get killed
if/when this happens. */
sa.sa_handler = SIG_IGN;
sigemptyset (&sa.sa_mask);
sa.sa_flags = 0;
sigaction (SIGPIPE, &sa, NULL);
/* Set the host running the SMTP server. LibESMTP has a default port
number of 587, however this is not widely deployed so the port
is specified as 25 along with the default MTA host. */
smtp_set_server (session, "127.0.0.1:25");
/* Set the reverse path for the mail envelope. (NULL is ok)
*/
smtp_set_reverse_path (message, "test@test.com");
/* RFC 2822 doesn't require recipient headers but a To: header would
* be nice to have if not present. */
smtp_set_header (message, "To", NULL, NULL);
smtp_set_header (message, "Subject", " test mail");
smtp_set_header_option (message, "Subject", Hdr_OVERRIDE, 1);
fprintf(stderr,"%s\n","smtp_set_server.");
if ((fp = fopen ("test-mail.eml", "r")) == NULL) {
fprintf (stderr, "can't open mail file: %s\n", strerror (errno));
return (1);
}
smtp_set_message_fp (message, fp);
smtp_add_recipient (message,"yourQQ@qq.com");
/* Initiate a connection to the SMTP server and transfer the
message. */
if (!smtp_start_session (session)){
fprintf (stderr, "SMTP server problem %s\n",
smtp_strerror (smtp_errno (), buf, sizeof buf));
}
else{
/* Report on the success or otherwise of the mail transfer.
*/
status = smtp_message_transfer_status (message);
printf ("%d %s", status->code,
(status->text != NULL) ? status->text : "\n");
}
/* Free resources consumed by the program.
*/
smtp_destroy_session (session);
if(fp != NULL){
fclose(fp);
}
return 0;
}
3、把上面的代码写入sendmail.c,并把里面的"yourQQ@qq.com"替换成你自己的QQ邮箱地址或者其它邮箱地址,然后用下面命令编译
gcc -std=c99 -Wall `libesmtp-config --cflags` -o sendmail sendmail.c -lesmtp
4、同目录下新建test-mail.eml文件,里面内容随便自己填。
5、运行
./sendmail