邮件监控怎么做啊?有例子吗?(300分)

  • 主题发起人 主题发起人 chensoft
  • 开始时间 开始时间
C

chensoft

Unregistered / Unconfirmed
GUEST, unregistred user!
关于监视局域网内邮件收发以及拦截的方法,请赐教!谢谢!
分数不够可以再开!
 
这个难度有点大.

除非用代理上网,你做个代理软件,把所以发到 25 端口的数拦下来.
 
拦截Socket的API,对端口25的请求做转发,换一个端口发送,而那个端口接收到消息后,用未拦截的Socket请求25端口发送.当然,如果邮件不被允许发送,则拦截,不继续外发.
 
话题1946872的标题是: 编写邮件监控程序时,如何检测出邮件服务器上有几封未读邮件? (100分)
分类:Internet/TCPIP nest (2003-06-12 16:28:00)
编写邮件监控程序时,如何检测出邮件服务器上有几封未读邮件?
我试过了Indy,Mail2000等控件,好像都只能检测出有多少邮件,而无法知道有多少未读的!
大家有何良策?

iDevCN (2003-06-12 20:59:00)
使用UIDL判断UIDL下载的信息以前下载过没有,就可以了

nest (2003-06-13 9:36:00)
不是很明白,我自己这样试了一下,先接收一封未查看邮件的UIDL串,而后到网页上直接打开查看该封邮件,而后再接收UIDL串,发现两次接收的UIDL串和邮件头都是一样的!
是不是我的做法有误?能否说得更明白些?或写个简单的例子给我,我的邮件试nest@263.net,谢谢

iDevCN (2003-06-13 13:36:00)
服务器是不能判断是否是新邮件,判断由客户端进行,如果你以前下载或者是使用UIDL命令后
你的客户端记录下UIDL的UIDL串,这样,下次再UIDL时候,你再与前一茨的比较有无变化,以此来判断是否有新邮件,
通过WEB方式,是因为WEB的脚本对POP3的邮件信息做了特殊的处理,才有已经阅读和未阅读
的分类,邮件服务器本身不能做判断,POP3/ESMTP协议无此功能定义.

pcsunflower (2003-06-13 14:06:00)
LAST 命令
不是所有服务器都支持
一般使用UIDL判断以前下载过没有[:D]

nest (2003-06-13 14:49:00)
但是为什么我上面那样试,却发现两次接收的UIDL串都是一样的?

yb33 (2003-06-16 12:15:00)
对,你两次接收的UIDL串都是一样的。
把第一次保存成文件,给自己发一封邮件,然后再UIDL,你看看就会不一样了

飞来石 (2003-07-05 15:07:00)
监视POP3信箱



本 文 将 向 大 家 介 绍 怎 样 编 写自 己 的 信 箱 监 视 程 序, 程 序 将 直 接 调 用WinSock 函 数 来 进 行网 络 通 信。 除 了 具 备WinSock 编 程 知 识 之 外, 还 必 须 了 解POP3 协 议。 下 面 是 对POP3 的 一 个 粗 略 的 介 绍, 读 者 可 以 参 看RFC 1225 更 为 详 细 地 了 解 该 协 议。


一、 关 于POP3 协 议

POP3 服 务 器 程 序 通 常 在TCP 端 口110 提 供 服 务。 当 客 户 想 要 使 用 服 务 时, 它 便 与 服 务 器 建 立 一个TCP 连 接。 一 旦 连 接 建 立,POP3 服 务 器 就 向 客 户 发 送 一 条欢 迎 消 息。 然 后 客 户 开 始 给 服 务 器 发 送 命 令, 服 务 器 则 给出 相 应 的 回 答。POP3 的 命 令 由 一 个 关 键 词 或 者 关 键 词 加 参数 组 成。 每 个 命 令 以 回 车 换 行(0xD0xA) 作 为 结 束 标 志。 对于 所 有 的 命 令,POP3 服 务 器 都 会 提 供 一 个 回 答。 服 务 器 的回 答 由 一 个 状 态 标 志 加 一 些 附 加 信 息 组 成。 目 前 使 用 的两 个 标 志 是“ +OK” 和“ -ERR”, 分 别 表 示 客 户 的 命 令 是 否合 法。 所 有 的 回 答 也 是 以 回 车 换 行 结 束。   与 本 文 讨 论 的 话 题 相 关 的 四 个POP3 命 令 是USER、PASS、LIST 和QUIT。

USER 命 令

格 式USER name


其 中name 是 用 户 在 该POP3 服 务器 上 的 用 户 标 识。 客 户 应 该 在 接 到 服 务 器 的 欢 迎 消 息 后或 者 在 上 一 个 USER 或 者PASS 失 败 之 后 可 以 发 送 此 命 令。


PASS 命 令

格 式PASS string


其 中string 为 该 用 户 的 密 码。客 户 在 发 送 了USER 命 令 并 且 收 到 了 +OK 的 回 答 之 后 方 可 发送 此 命 令。 如 果 用 户 名 和 密 码 都 正 确, 服 务 器 回 答 +OK,否 则 -ERR。


LIST 命 令

格 式LIST


如 果 该 用 户 有 邮 件, 则LIST 命令 会 回 答 +OK, 并 列 出 所 有 邮 件 的 标 识 符 和 大 小( 每 个 邮件 一 行), 最 后 一 个 仅 包 含 一 个 句 点 的 行(0xD0xA0x2E) 表 示整 个 回 答 的 结 束。 如 果 该 用 户 没 有 邮 件, 有 些 服 务 器 会 返回 -ERR, 有 些 在 可 能 返 回 一 个 +OK 和 一 个 仅 包 含 一 个 句 点的 行。 当 然, 客 户 必 须 在PASS 命 令 通 过 之 后 客 户 程 序 才 能给 服 务 器 发 送LIST 命 令。


QUIT 命 令



从POP3 服 务 器 上 退 出 登 录。

二、 实 现 相 关 函 数

接 下 来 我 们 按 照POP3 协 议 所 定 义的 通 信 规 则 来 实 现 一 个 名 叫POP3CheckMail 的 函 数, 只 要 调 用此 函 数, 我 们 就 可 以 检 测 信 箱 了。

下 面 的 代 码 是 用 与Delphi 4 兼 容的Pascal 语 言 实 现 的, 我 们 必 须 包 含WinSock 单 元, 并 且 在 调用 下 列 函 数 之 前 初 始 化 好WinSock 动 态 连 接 库。 初 始 化WinSock 动 态 连 接 库 的 代 码 如 下:

if WSAStartup( $002

wsadata)<>0 then Halt;


POP3CheckMail 的 原 型 如 下:


function POP3CheckMail(Email

Password:String;var MailList:TStringList;var ErrorMsg:String):Bool;


参 数 说 明:


Email 和Password 分 别 为 用 户 的email 信 箱 名 和 口 令。


变 量 参 数MailList 用 于 返 回 邮件 的 标 识 和 大 小,MailList.Count 表 示 邮 件 的 封 数。


变 量 参 数ErrorMsg 返 回 出 错 消息。


以 下 是POP3CheckMail 及 其 它 所 用到 的 函 数 的 实 现 代 码。


Connect_Server 函 数


功 能: 与 指 定 的 主 机 建 立 一个TCP 连 接, 返 回 一 个Socket 描 述 符。 参 数host 指 定 主 机 的 名字,Port 指 定 端 口 号。


function Connect_Server(host:string;Port:integer):integer;


var i:integer;


p:^LongInt;


phe:pHostEnt;


sin:sockaddr_in;


begin


sin.sin_family:=AF_INET;


sin.sin_port:=htons(Port);


//Get the IP for host

allowing for dotted decimal


phe:=gethostbyname(pchar(host));


if phe<>nil


then begin


p:=Pointer(phe^.h_addr_list^);


sin.sin_addr.s_addr:=p^;


end


else begin


i:=inet_addr(PChar(Host));


if i<> -1 then sin.sin_addr.S_addr:=i


end;


//create a socket


Result:=socket(PF_INET

SOCK_STREAM

0);


if (Result=INVALID_SOCKET) then Exit;


//connect to server


if Connect(Result

sin

sizeof(sin))=SOCKET_ERROR


then begin {Error handling} end;


end;



Write_Socket 函 数

功 能: 向Socket 写 入 一 个 字 符串。


function Write_Socket(sockfd:Integer; const s:string):Integer;


begin


result:=Winsock.Send(sockfd

pointer(s)^

Length(s)

0)


end;



Socket_Readline 函 数

功 能: 从Socket 上 读 取 一 行。


function Socket_Readline(sockfd:Integer):String;


//Read until #10


var S:String; buf:array[0..1]of Char;


n:Cardinal;


begin


buf[0]:= #0;buf[1]:= #0; S:=‘';


n:=recv(sockfd

Buf

1

0);


while n>0 do begin


buf[1]:= #0;


S:=S +buf;


if (buf[0]= #10) then Break;


n:=recv(sockfd

buf

1

0);


end;


Result:=Trim(S);


end;



Pop3Response 函 数

功 能: 读 取POP3 服 务 器 的 一 行返 回 信 息, 如 果 是“ +OK” 则 函 数 返 回TURE, 如 果 是“ -ERR” 则 返 回FALSE。


function Pop3Response(Sockfd:Integer):Bool;


var S: string;


begin


S:=socket_readline(sockfd);


if copy(s

1

3)=‘ +OK' then Result:=True


else {if copy(s

1

4)=‘ -ERR' then }Result:=False;


end;



POP3CheckMail 函 数

功 能: 检 测 名 字 为email 的 信 箱,如 果 有 新 邮 件, 则 通 过 变 量 参 数MailList 将 每 一 封 邮 件 的 大小 返 回。


function POP3CheckMail


(Email

Password:String;var MailList:


TStringList;var ErrorMsg:String):Bool;


var sockfd

i:integer;


S

Host

User:String;


begin


Result:=False; ErrorMsg:=‘';


if MailList=nil then Exit;


S:=Trim(Email);


i:=Pos(‘@'

Email);


User:=Trim(Copy(S

1

i -1));


Host:=Trim(Copy(S

i +1

Length(Email) -i));


MailList.Clear;


if (user=‘')or(host=‘') then begin


ErrorMsg:=‘Invalid email address.';exit; end;


if (Host[1]=‘[')and (Host[Length(host)]=‘]')


then begin Host[1]:=‘ ';Host[Length(host)]:= #0;end;


Host:=Trim(host);


sockfd:=Connect_Server(Host

110);


if not Pop3Response(sockfd)then begin ErrorMsg:=


‘Cannot connect to server';exit; end;


Write_Socket(sockfd

‘USER ' +User + #13 #10);


IF NOT POP3Response(sockfd) then begin ErrorMsg:=


‘USER failed'; Exit;end;


Write_Socket(sockfd

‘PASS ' +Password + #13 #10);


IF NOT POP3Response(sockfd) then begin ErrorMsg:=


‘PASS failed'; Exit;end;


Write_Socket(sockfd

‘LIST' #13 #10);


POP3Response(sockfd);


while true do begin


s:=Socket_readline(sockfd);


if s=‘.' then BREAK;


MailList.Add(S);


end;


Write_Socket(sockfd

‘QUIT' #13 #10);


Closesocket(sockfd);


Result:=True;


end;



三、 邮 件 的 检 测

下 面 我 们 来 看 一 个 使 用POP3CheckMail 函 数 的 简 单 示 例。


var MailList:TstringList;


ErrorMsg:String;


...


MailList:=TstringList.Create;


POP3CheckMail(‘simon_liu@263.net'



‘mypassword'

MailList

ErrorMsg);


If MailList.Count>0 then


MessageBox(0

Pchar(‘You have ' +IntToStr


(MailList.Count) + ‘ new messages!')



‘New Message!'

MB_ICONINFORMATION)


Else if ErrorMsg=‘' then MessageBox


(0

‘No message!'

‘'

0)


Else MessageBox(0

Pchar(ErrorMsg)

‘Error'

0);


MailList.Free;



如 果 你 仔 细 阅 读 了POP3CheckMail 函数 的 实 现 代 码, 你 会 发 现 此 函 数 除 了 可 以 获 取 邮 件 的 封数 之 外, 还 可 以 获 得 每 一 封 邮 件 的 大 小。 你 可 以 通 过POP3CheckMail 函 数 的 变 量 参 数MailList 的Strings 数 组 来 获 取 邮 件 的 大 小。

实 现 了POP3CheckMail 函 数, 再 在此 基 础 上 编 写 一 个POP3 信 箱 的 监 视 程 序 就 变 得 很 简 单 了。你 可 以 通 过 一 个 定 时 器 来 定 期 地 调 用POP3CheckMail 函 数, 这样 你 就 可 以 监 视 某 个email 信 箱 了。 假 若 你 想 要 同 时 监 视 多个email 信 箱, 只 要 为 每 一 个 信 箱 创 建 一 个 线 程 并 且 在 线 程中 定 期 调 用POP3CheckMail 函 数 即 可。 你 的 程 序 中 如 果 没 有 使用Delphi 的 控 件, 那 么 一 个 完 整 的 信 箱 监 视 程 序 可 能 只 有60K 左 右。
 
兄弟们,多多指点!
 
weiliu,
你还没搞懂楼主想要什么
 
顶者有分
 
人居然这么少!
 
用indy是可以的。。
至于有多少没有读,我想刚从邮件服务器上下载下来的时候应该就是算做未读,因为对于这个客户端来说它是没有处理果这些信息的,只有当你下载后做一定的标记后才能判断时候是否已读
 
用 WinPCap 可以.监听所有 TCP 连接
 

Similar threads

D
回复
0
查看
824
DelphiTeacher的专栏
D
D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
1K
DelphiTeacher的专栏
D
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
后退
顶部