侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 130562 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

将postfix收发邮件记录到mysql

2023-11-23 星期四 / 0 评论 / 0 点赞 / 34 阅读 / 10584 字

原来的方法修改地方太多,比较麻烦,最近看到一篇文章 http://blog.csdn.net/qidizi/article/details/8779769改动很少,将from to 合到一条日志里面,

原来的方法修改地方太多,比较麻烦,最近看到一篇文章 http://blog.csdn.net/qidizi/article/details/8779769改动很少,将from to 合到一条日志里面,甚是方便,先给记录下来,以便后期查看

修改方法跟原博主一样global/recipient_list.h 在 typedef struct RECIPIENT 里面加,我是加到24行的

typedef struct RECIPIENT {    char * letterInfo;      /* new add */    long    offset;			/* REC_TYPE_RCPT byte */    const char *dsn_orcpt;		/* DSN original recipient */    int     dsn_notify;			/* DSN notify flags */    const char *orig_addr;		/* null or original recipient */    const char *address;		/* complete address */    union {				/* Application specific. */	int     status;			/* SMTP client */	struct QMGR_QUEUE *queue;	/* Queue manager */	const char *addr_type;		/* DSN */    }       u;} RECIPIENT;

global/deliver_request.c postfix版本不同,代码有部分更新,我这变成了 318行,

recipient_list_add(&request->rcpt_list, rcpt_buf->offset, vstring_str(rcpt_buf->dsn_orcpt),    rcpt_buf->dsn_notify,  vstring_str(rcpt_buf->orig_addr), vstring_str(rcpt_buf->address));    request->rcpt_list.info[request->rcpt_list.len - 1].letterInfo = mystrdup(request->sender); /* add */    }

global/recipient_list.c 加到151行

void    recipient_list_add(RECIPIENT_LIST *list, long offset,			           const char *dsn_orcpt, int dsn_notify,			           const char *orig_rcpt, const char *rcpt){    int     new_avail;    if (list->len >= list->avail) {	new_avail = list->avail * 2;	list->info = (RECIPIENT *)	    myrealloc((void *) list->info, new_avail * sizeof(RECIPIENT));	list->avail = new_avail;    }    list->info[list->len].letterInfo = mystrdup("");    /* add */    list->info[list->len].orig_addr = mystrdup(orig_rcpt);    list->info[list->len].address = mystrdup(rcpt);    list->info[list->len].offset = offset;    list->info[list->len].dsn_orcpt = mystrdup(dsn_orcpt);    list->info[list->len].dsn_notify = dsn_notify;    if (list->variant == RCPT_LIST_INIT_STATUS)	list->info[list->len].u.status = 0;    else if (list->variant == RCPT_LIST_INIT_QUEUE)	list->info[list->len].u.queue = 0;    else if (list->variant == RCPT_LIST_INIT_ADDR)	list->info[list->len].u.addr_type = 0;    list->len++;}

global/log_adhoc.c 107行 加上要增加的from和recipient->letterInfo

vstring_sprintf(buf, "%s: from=<%s>, to=<%s>", id, recipient->letterInfo, recipient->address);    if (recipient->orig_addr && *recipient->orig_addr	&& strcasecmp_utf8(recipient->address, recipient->orig_addr) != 0)

到这就可以将from和to记录到一条里面,结果如下

2017-03-03 20:58:04 postfix/smtpd[1405]: disconnect from unknown[118.44.22.82] ehlo=1 mail=1 rcpt=1 data=1 quit=1 commands=52017-03-03 20:58:06 postfix/smtp[1409]: CF4D6322472D: from=<[email protected]>, to=<[email protected]>, relay=mx3.qq.com[184.105.206.85]:25, delay=2.5, delays=0.17/0.02/0.93/1.4, dsn=2.0.0, status=sent (250 Ok: queued as )

最终是要记录到数据库里面的,那么再新建一个putmysql.h

#include <mysql.h>#include <stdio.h> void put_mysql(const char *qid, const char *sender, const char *recipient, const char *relay, const char *status, const char *result){    MYSQL mysql;    MYSQL_RES *res;    int flagone;    int flagtwo;    char rid[12] = {0};    char buf[512]={0};    char bufs[512] = {0};    mysql_init(&mysql);    /*  postfix队列id是12位,如果收件MTA也是postfix        则会在result返回 250 2.0.0 Ok: queued as 987EA61049B1          这里面取最后12位保存为rid */    if (strlen(result)>12){        sprintf(rid,strncpy(rid,result+(strlen(result)-12),12));           }else{        sprintf(rid,result);           }        msg_info("%s",rid);    if(!mysql_real_connect(&mysql, "127.0.0.1", "root", "westhost", "test", 0, NULL, 0))    {        msg_info("Failed to connect to Mysql: %s", mysql_error(&mysql));    }    /*  如果qid已经存在,则是中继,更新记录即可 */    sprintf(buf,"select qid from test where (rid=/"%s/" and recipient=/"%s/") OR (qid=/"%s/" and recipient=/"%s/")",qid,recipient,qid,recipient);        flagone = mysql_query(&mysql,buf);    if(flagone)    {        msg_info("SELECT error: %s", mysql_error(&mysql));    } else {        res = mysql_store_result(&mysql);        if((unsigned long)mysql_num_rows(res)>0){            sprintf(bufs,"update test set rid=/"%s/", relay=/"%s/", stat=/"%s/", result=/"%s/" where (qid=/"%s/" and recipient=/"%s/") OR (rid=/"%s/" and recipient=/"%s/")",rid,relay,status,result,qid,recipient,qid,recipient);            flagtwo = mysql_query(&mysql,bufs);            if(flagtwo){                msg_info("UPDATE error: %s", mysql_error(&mysql));            }else {                msg_info("Retrieved %lu rows update sucessed", (unsigned long)mysql_num_rows(res));            }        } else{            /*  不存在qid的则表示是第一次发送,新增记录 */            sprintf(bufs,"insert into test (qid,sender,recipient,stime,relay,stat,result,rid) values (/"%s/",/"%s/",/"%s/",NOW(),/"%s/",/"%s/",replace(/"%s/",/"///"/",/"'/"),/"%s/")",qid,sender,recipient,relay,status,result,rid);            flagtwo = mysql_query(&mysql,bufs);            if(flagtwo){                msg_info("INSERT error: %s", mysql_error(&mysql));            }else{                msg_info("insert sucessed");            }                   }    }    mysql_close(&mysql);}

最后在global/log_adhoc.c #include <putmysql.h>最后在加上putmysql调用

msg_info("%s", vstring_str(buf));put_mysql(id, recipient->letterInfo, recipient->address, relay, status, dsn->reason);     /* add */

编译安装就可以了,最后大功告成,日志如下,数据库里面也有相应的记录了。

2017-03-03 21:23:58 postfix/qmgr[7797]: 08CE520449CD: from=<[email protected]>, size=1695, nrcpt=1 (queue active)2017-03-03 21:24:00 postfix/smtp[7804]: 08CE520449CD: from=<[email protected]>, to=<[email protected]>, relay=mx3.qq.com[184.105.206.85]:25, delay=2.8, delays=0.19/0.01/1.2/1.4, dsn=2.0.0, status=sent (250 Ok: queued as )2017-03-03 21:24:00 postfix/smtp[7804]: insert sucessed.2017-03-03 21:24:00 postfix/qmgr[7797]: 08CE520449CD: removed

这里面dsn返回多个属性,具体如下

DF1DA20449CC: from=<[email protected]>, to=<[email protected]>, relay=mx3.qq.com[184.105.206.82]:25, delay=18, delays=6.5/0.01/2.9/8.4, dsn=2.0.0, status=sent (250 Ok: queued as )dsn->status        2.0.0  (sent.c里面定义的,发送成功为2.0.0)dsn->action        relayeddsn->reason        250 Ok: queued asdsn->dtype        smtpdsn->dtext        250 Ok: queued as dsn->mtype        dnsdsn->mname        mx3.qq.com 

如果发送状态一直是 deferred,达到queue限制时间后会直接退信,这种状态不是bounced

2017-03-10 09:07:35 postfix/cleanup[11581]: E2E14207B661: message-id=<[email protected]>2017-03-10 09:07:35 postfix/bounce[11579]: 889F5207B65B: sender non-delivery notification: E2E14207B661

这种也可以直接更新到数据库里面,算作是退信,那么要修改

src/bounce/bounce_notify_service.c

#include "../global/putmysqlb.h"if (bounce_status == 0)		    msg_info("%s: notify_service sender non-delivery notification: %s",			     queue_id, STR(new_id));            put_mysqlb(queue_id, STR(new_id));   /*  new add */	    } else {		/* No applicable recipients found - cancel this notice. */		(void) vstream_fclose(bounce);		if (count == 0)		    bounce_status = 0;	    }

putmysqlb.h

#include <mysql.h>#include <stdio.h> void put_mysqlb(const char *qid, const char *rid){    msg_info("qid: %s rid: %s",qid,rid);    char bufs[100] = {0};    char buf[200]= {0};    int flag;    int flagone;    MYSQL mysql;    MYSQL_RES *res;    mysql_init(&mysql);        if(!mysql_real_connect(&mysql, "127.0.0.1", "root", "westhost", "test", 0, NULL, 0))    {        msg_info("Failed to connect to Mysql: %s", mysql_error(&mysql));    }    sprintf(buf,"select qid from test where qid=/"%s/"",qid);    msg_info("buf: %s/r/n",buf);    flagone = mysql_query(&mysql,buf);    if(flagone)    {        msg_info("SELECT error: %s", mysql_error(&mysql));    } else {        res = mysql_store_result(&mysql);        sprintf(bufs,"update test set rid=/"%s/", stat=/"%s/" where qid=/"%s/"",rid,"bounced",qid);        flag = mysql_query(&mysql,bufs);        if(flag){            msg_info("UPDATE error: %s %s/r/n", mysql_error(&mysql),bufs);        }else {            msg_info("Retrieved %lu rows update sucessed", (unsigned long)mysql_num_rows(res));        }    }      mysql_close(&mysql);}

下面两个文件也有 sender non-delivery notification 还不清楚具体哪类退信会调用,暂不修改

src/bounce/bounce_notify_verp.c

src/bounce/bounce_one_service.c

这几个文件了

如果编译时提示 警告: 隐式声明与内建函数 ‘sprintf’ 不兼容,添加下面两个头文件

#include <stdio.h> #include <stdlib.h> 

如果提示 xxx 没有原型

因为自定义的函数都是在msg_info后面执行的,所以可以在/src/util/msg.h里面添加声明

extern void put_mysql(const char *, const char *, const char *, const char *, const char *, const char *);extern void put_bounced(const char *, const char *);

广告 广告

评论区