求邮件服务器原理,谢谢!(分不多,但是已是我所有的分了)(260分)

  • 主题发起人 主题发起人 tomore
  • 开始时间 开始时间
T

tomore

Unregistered / Unconfirmed
GUEST, unregistred user!
最好能提供例子
需要支持 smtp,pop3
 
没有人问答呀?
 
原理就不会了
如何写看delphi的demo
 
可以到http://www.longen.com/处看看!
 
delphi的控件会有问题的
自己写也太麻烦
看看RFC
 
hermes的邮件服务器源码,为什么少了一个wsocket.dcu文件,编译不能通过,请教哪位
知道问题所在?
 
一. 设计思路

---- Email 系统采用C/S 结构。当用户想发送邮件时或收取邮件时在客户机上运行任意一个客户端程序,如Foxmail。在菜单’工具->选项’的邮件服务器里填上运行我们服务器程序的主机名。服务器主机24小时一直运行我们的服务器端程序,SMTP和POP3服务器程序分别在25端口和110端口侦听连接请求。当用户发信时,首先客户端会与服务器端建立Socket连接。然后开始一应一答的Client/Server间的通信。发信和收信时建立连接后服务器端分别要发送一个’250 OK’ 和’+OK pop3 server is ready ’的应答。客户端收到此应答后开始发送SMTP或POP3命令。POP3通信时一般最开始的命令是’user ‘和’pass’或’ apop’用以进行身份验证。注意由于POP3会话有3个状态,某些命令只在某特定状态下有效。当用户进行完所有的操作后发送一个’quit’命令。服务器端收到此命令即终止此次socket连接并继续侦听其他的连接请求。注意:POP3通信时客户端在Transaction状态下’quit’则进入update状态。如果从Authorization状态下’quit’则终止通信,而不进入Update状态。如果客户端不通过’quit’命令终止连接,POP3会话不会进入Update状态。而只有在Update状态下收到’quit’命令后服务器才会在断连前把标志为已删的邮件进行物理删除。

---- 二. 代码实现(以POP3为例)

---- 自定义TPOP类的描述:

SessionState = ( Init,Authorization, Transaction,Update);
TPop=class (TComponent)
public
UserName:string;//Email帐户名
PassWord:string; //Email口令
ReceText:Pchar; //server端收到的字符串
PopState:SessionState;
//pop状态:
init or authorization or transaction or update
MsgCount:integer; //邮件总数
SizeCount:integer; //邮件总大小
ReplyString:string;//服务器端发送的应答信息
DeleIndex:byte;//用户要删的邮件序号
ListIndex:byte;//list方法 的参数:
用户要列出的序号为listindex的邮件信息
RetrIndex:byte;//retr方法的参数:
用户要取序号为retrindex的邮件
TopIndex:byte; //top方法的参数
QuitFlag:boolean;//用户如果通过quit命断连则此变量为true;
反之(此时要把f_dele都置回0)
OldMsgCount:integer;//旧邮件数:Last 命令返回
//邮件头的各个域
HMsgId:string;
HReplyTo:string;
HDate:string;
HFrom:string;
HTo:string;
HSubject:string;
HMIME_Ver:real;
HContent_Type:string;
HContent_Transfer_Encoding:string;
HText:string;
//所有POP3服务器必须支持的命令
procedure user;
function pass:boolean;
procedure stat;
procedure dele;
procedure list;
procedure retr;
procedure noop;
procedure rset;
procedure aquit;
procedure tquit;
//扩展的可选择实现的POP3 命令
procedure top;
procedure last;
procedure apop;
procedure uidl;
end;

---- 1. 建立连接

---- 我们可以看到利用了Tclientsocket后客户端请求建立连接只需下面的代码。

with ClientSocket do
begin
Host := Server;
Active := True;
end;

---- 服务器端利用TserverSocket,一直在侦听110端口,若客户端有连接请求,则ServerSocketAccept事件会被激活,建立起连接。

procedure TMyForm.ServerSocketAccept(Sender: TObject;
Socket: TCustomWinSocket);
begin
Statusbar1.Panels[0].Text :=
'连接到 ' + Socket.RemoteAddress;
//pop对象初始化
pop:=TPop.Create(nil);
pop.PopState:=init;
pop.LoginResult:=false;
pop.QuitFlag:=false;
ServerSocket.Socket.Connections[0]
.sendtext('+OK ibonc pop3 server is ready'+crlf);

end;

---- 2. 通信

---- 服务器端收到客户端发来的信息,则会激活ServerSocketClientRead事件,通过ServerSocket的Socket.ReceiveText可以得到信息的内容。

procedure TMyForm.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var temp_command :string;
//存放接收到的命令行,并做去crlf的处理
begin
temp_command:=Socket.ReceiveText;
//to remove the crlf in command line
temp_command:=trim(copy(temp_command,1,
pos(crlf,temp_command)-1));
pop.ReceText:=pchar(temp_command);
if pop.popstate=init then
if strLIComp(pop.ReceText,'user ',5)=0 then
pop.user
else
ServerSocket.Socket.Connections[0]
.sendtext('-ERR user name please')
else if pop.popstate=authorization then
begin
if strLIComp(pop.ReceText,'pass ',5)=0 then
pop.pass
else if strIComp(pop.ReceText,'quit')=0 then
pop.aquit
else
ServerSocket.Socket.Connections[0]
.sendtext('-ERR pass word please');
end
else if pop.popstate=transaction then
begin
if strIComp(pop.ReceText,'stat')=0 then
pop.stat
else if strLIComp(pop.ReceText,'dele ',5)=0 then
pop.dele
else if strLIComp(pop.ReceText,'list',4)=0 then
pop.list
else if strLIComp(pop.ReceText,'retr ',5)=0 then
pop.retr
else if strIComp(pop.ReceText,'noop')=0 then
pop.noop
else if strIComp(pop.ReceText,'rset')=0 then
pop.rset
else if strIComp(pop.ReceText,'quit')=0 then
pop.tquit
else if strIComp(pop.ReceText,'last')=0 then
pop.last
else if strLIComp(pop.ReceText, 'apop ',5)=0 then
pop.apop
else if strLIComp(pop.ReceText, 'uidl ',5)=0 then
pop.uidl
else
ServerSocket.socket.connections[0]
.sendtext('-ERR no such command yet'+crlf);
end
end;

---- 3. 关闭连接

procedure TMyForm.ServerSocket
ClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
ServerSocket.Active := False;
//如果client端没有通过quit 命令断连,
则在断连时要把那些f_dele置为0
if pop.QuitFlag=False then
begin
MyForm.query11.Close;
MyForm.query11.Params[0].Asstring:=pop.UserName;
MyForm.query11.prepare;
MyForm.query11.execsql;
end;
end;




 
呵呵!最近刚在研究我可以拷2段代码给你,是smtp和pop的,我的邮件服务器好了,用indy的控间就好了

smtp的
procedure TFCoMail.SmtpServerExecute(AThread: TIdPeerThread);
var
ClientStr:String;
smtpInfo:TSmtpInfo;
i:integer;
begin
smtpInfo:=Pointer(AThread.Data);
ClientStr:=AThread.Connection.ReadLn;
GetSmtpInfo(ClientStr,smtpInfo);//取得客户端消息
case SmtpInfo.State of
HELO,FROM,SENDTO:
begin
AThread.Connection.WriteLn('250 CoMail OK');
end;
EHLO:
Begin
AThread.Connection.WriteLn('250 CoMail OK');
end;
DATA:
begin
AThread.Connection.WriteLn('354 Send the mail data, end with . ');
end;
DataEnd:
begin
AThread.Connection.WriteLn('250 CoMail OK');
for I:=0 to smtpinfo.CC.Count-1 do
begin
AddLog(format('主机%s向%s发送了邮件',[smtpinfo.dsn,smtpinfo.cc.strings]))
end;
SaveSmtpMail(SmtpInfo);
SmtpInfo.CC.Clear;
smtpInfo.Mailbody.Clear;
end;
QUIT:
begin
AThread.Connection.WriteLn('221 CoMail Say GoodBye to You');
AThread.Connection.Disconnect;
end;
ReadBody:
begin
SmtpInfo.Mailbody.Add(ClientStr);
end;
end;
end;

pop的
procedure TFCoMail.PopServerExecute(AThread: TIdPeerThread);
var
ClientStr,Cmd,Param,UserName,ID:String;
UserInfo:TUserInfo;
begin
UserInfo:=Pointer(AThread.Data);

ClientStr:=AThread.Connection.ReadLnWait;//('',500);
Memo1.Lines.Add(ClientStr);
if ClientStr<>'' then
Memo1.Lines.Add(ClientStr);
if pos('top',Lowercase(ClientStr))=0 then
begin
Cmd:=upperCase(copy(ClientStr,1,4));
Param:=trim(copy(ClientStr,5,length(ClientStr)-4));
end
else
begin
Cmd:=upperCase(copy(ClientStr,1,3));
Param:=trim(copy(ClientStr,5,length(ClientStr)-3));
end;
if Cmd='USER' then //此命令与下面的pass命令若成功,将导致状态转换
begin
UserName:=Param;
UserInfo.UserName:=username;
if CheckUser(UserName) then
AThRead.Connection.WriteLn('+OK User Accept Send Your Password')
else
begin
AThRead.Connection.WriteLn('-ERR No such a user');
end;
end
else if Cmd='PASS' then
begin
UserInfo.PassWord:=Param;
if CheckPass(UserInfo.UserName,Param) then
AThRead.Connection.WriteLn('+OK Password Accept')
else
AThRead.Connection.WriteLn('-ERR PassWord incorrectly');
end
else if Cmd='APOP' then //Digest是MD5消息摘要
begin
end
else if Cmd='STAT' then //请求服务器发回关于邮箱的统计资料,如邮件总数和总字节数
begin
AThRead.Connection.WriteLn(AddUserMailInfo(UserInfo));
end
else if Cmd='UIDL' then //返回邮件的唯一标识符,POP3会话的每个标识符都将是唯一的
begin

if param='' then
ListMail(param,UserInfo,AThread)
else
UIDLMail(UserInfo,param,AThread);
end
else if Cmd='LIST' then // 返回邮件数量和每个邮件的大
begin
ListMail(param,UserInfo,AThread);
end
else if Cmd='RETR' then //返回由参数标识的邮件的全部文本
begin
SendMailOnOrder(param,UserInfo,AThread);
end
else if Cmd='DELE' then //服务器将由参数标识的邮件标记为删除,由quit命令执行
begin
DeleteMail(param,UserInfo,AThread);
end
else if Cmd='TOP' then // 服务器将返回由参数标识的邮件前n行内容,n必须是正整数
begin
ID:=copy(param,1,pos(' ',Param)-1);
Delete(param,1,pos(' ',Param));
TopMail(ID,Param,UserInfo,AThread);
end
else if Cmd='QUIT' then //更新     
begin
Addlog(format('用户%s接收到%d封邮件',[UserInfo.UserName,UserInfo.UserMail.count]));
AThread.Connection.WriteLn('+OK Dewey CoMail POP3 server signing off');
AThread.Connection.Disconnect;
end
else if Cmd='NOOP' then
begin
AThread.Connection.WriteLn('+OK ');;
end
else if ClientStr='' then
begin
// AThread.Connection.WriteLn('-err');;
end;

end;


其实只要查RFC的文档写也不难


 
indy有原代码的哟[:)]
 
没看见有邮件服务器的DEMO啊,只看到一个客户端和SMTP的。晕倒
 
grays,能否给源码给我一份参考一下,我只需要SMTP部分。。。可以吗?我的邮箱
webmaster@51kk.com,我只是需要邮件来收到一些信息后处理,不是真正做邮件服务器。
 
看pop3和smtp的rfc吧
或者看看sendmail的源代码。
 
后退
顶部