基于raw smtp用php实现简易的smtp客户端

任务需求:一个会议投稿系统,在作者提交论文摘要时自动向作者发送一封确认邮件。
(注:投稿系统使用的是myreview )
仔细考虑一下,这个任务可以有以下几种方式完成:

  1. 在服务器上配置sendmail服务,使用php中的的mail函数发送邮件;
  2. 在服务器上安装mutt + msmtp,或者在服务器上安装其它的smtp客户端程序,使用smtp客户程序发送邮件
  3. 写一个C/S程序,每当有作者提交论文时,服务器上的client端程序即把邮件内容组合好,然后通知在我的电脑上监听的server端程序,server端程序于是调用我的电脑上的邮件发送脚本来发送邮件。这个c/s程序可以用java, c, php等来写
  4. 用nc或者telnet使用raw smtp协议来发送邮件

从用linux以来就对sendmail这个服务没有好感,方法一放弃。也不想在服务器上安装附加的软件,所以方法二放弃。对比起来,方法四比方法三更简单一些。

方法四的思路:使用tcpdump拦截一次完整的smtp发信过程,然后写程序模拟这个过程。
首先启动tcpdump对来往的数据包进行监控:

[root@jcwkyl review]# tcpdump -vvv -t -X -s 1500 -w data host mail.jlu.edu.cn
-vvv表示用最详细的格式来记录捕获的数据包,-t表示不记录时间戳,-X表示用hex和ascii显示数据包内容,-s表示显示长度为1500而不是默认的68,-w表示输出到data文件中。

同时,发送一封邮件。
[whb@jcwkyl bash]$ echo "mail content" | mutt -s "test subject" jcwkyl@gmail.com

看这边tcpdump:
[root@jcwkyl review]# tcpdump -vvv -t -X -s 1500 -w data host mail.jlu.edu.cn
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 1500 bytes
Got 34

捕获了34个数据包。查看记录文件:
[root@jcwkyl review]# tcpdump -vvv -t -X -s 1500 -r data | less

输出很多,从其中可以看到数据往来的格式,截取其中三个数据包为例:
<!-- @page { size: 8.5in 11in; margin: 0.79in } P { margin-bottom: 0.08in } -->

IP (tos 0x0, ttl  61, id 51365, offset 0, flags [DF], proto: TCP (6), length: 63) mail.jlu.edu.cn.sm
tp > jcwkyl.gridlab.57415: P, cksum 0x9765 (correct), 1:12(11) ack 1 win 1448 <nop,nop,timestamp 203
2907544 165074058>
        0x0000:  4500 003f c8a5 4000 3d06 577f cac6 1038  E..?..@.=.W....8
        0x0010:  0a3c 385a 0019 e047 c0c6 7dbd eeb9 52bd  .<8Z...G..}...R.
        0x0020:  8018 05a8 9765 0000 0101 080a 792b b518  .....e......y+..
        0x0030:  09d6 d48a 3232 3020 4553 4d54 500d 0a    ....220.ESMTP..
IP (tos 0x0, ttl  64, id 34360, offset 0, flags [DF], proto: TCP (6), length: 52) jcwkyl.gridlab.574
15 > mail.jlu.edu.cn.smtp: ., cksum 0xebee (correct), 1:1(0) ack 12 win 46 <nop,nop,timestamp 165074
058 2032907544>
        0x0000:  4500 0034 8638 4000 4006 96f7 0a3c 385a  E..4.8@.@....<8Z
        0x0010:  cac6 1038 e047 0019 eeb9 52bd c0c6 7dc8  ...8.G....R...}.
        0x0020:  8010 002e ebee 0000 0101 080a 09d6 d48a  ................
        0x0030:  792b b518                                y+..
IP (tos 0x0, ttl  64, id 34361, offset 0, flags [DF], proto: TCP (6), length: 68) jcwkyl.gridlab.574
15 > mail.jlu.edu.cn.smtp: P, cksum 0x1dcb (incorrect (-> 0x8015), 1:17(16) ack 12 win 46 <nop,nop,t
imestamp 165074058 2032907544>
        0x0000:  4500 0044 8639 4000 4006 96e6 0a3c 385a  E..D.9@.@....<8Z
        0x0010:  cac6 1038 e047 0019 eeb9 52bd c0c6 7dc8  ...8.G....R...}.
        0x0020:  8018 002e 1dcb 0000 0101 080a 09d6 d48a  ................
        0x0030:  792b b518 4548 4c4f 206c 6f63 616c 686f  y+..EHLO.localho
        0x0040:  7374 0d0a                                st..


第一个数据包是服务器发给我的,内容就是:220 ESMTP,第二个数据包没有内容不用管它,第三个数据包也是我发给服务器的,数据内容是: EHLO/x20localhost/x0d/x0a
就这样在这34个数据包里找,把所有的从我发到邮件服务器的数据内容提取出来,最后的结果如下:
EHLO localhost/r/n
AUTH LOGIN/r/n
<para1>
<para2>
MAIL FROM:<whb@jlu.edu.cn>/r/n
RCPT TO:<jcwkyl@gmail.com>/r/n
DATA/r/n
Date: Fri, 1 5 Jan 2010 17:10 :06 +0800 /r/n
From: Email Address <addr@jlu.edu.cn>/r/n
To: jcwkyl@gmail.com/r/n
Subject: test subject/r/n
Message-ID: <20100115091 006 GA12962@jcwkyl.gridlab>/r/n
Mime-Version: 1.0/r/n
Content-Type: text/plain; charset=us-ascii/r/n
Content-Disposition: inline/r/n
User-Agent: Mutt/1.4.2.2i/r/n/r/n
mail content/r/n/x2e/r/n
QUIT/r/n
以上就是整个过程。注意邮件正文开始前有两个/r/n,邮件正文以/r/n/x2e/r/n结束。/r就是十六进制的/x0d,/n就是十六进制的/x0a。
上面的<para1>和<para2>本来是两个字符串,从上下文猜测是用来身份验证的,这里用<para1>和<para2>代表。

接下来就是写程序模拟这个过程,因为会议投稿系统是用php写的,所以就用php写程序模拟这个邮件发送过程,最终的代码如下:

被注释掉的mail函数是投稿系统以前的代码,mail函数之后是自己写的模拟邮件发送过程的代码。同样的功能很容易用其他语言实现。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值