如何才能不通过SMTP服务器直接发邮件给对方????(50分)

  • 主题发起人 主题发起人 dingdingmao
  • 开始时间 开始时间
同意CJF。
smtp服务器的作用在于:
You ->mail server(smtp)-> dest mail server(pop3)-> Dest
所谓不使用smtp, 无非就是变成了:
You ->dest mail server(pop3)-> Dest
实现的方法就是让自己的Client带有smtp功能。

 
Town:这样是没错,可关键在于如何让自已的CLIENT具有SMTP功能?
能否用QQ与我详谈。
QQ:81828019
 
我觉得,FOXMAIL的特快专递功能也就是直接查找收件者的POP3服务器,然后用
SMTP协议和该POP3服务器通信,连接的端口仍然是SMTP端口,语法也仍然是SMTP语法,
此时该POP3服务器在特快专递的通信过程中也充当了普通SMTP服务器功能,
所不同的只是接收邮件者是该POP3服务器上自己的用户的邮件,而不是需要转发出去的。
SMTP认证也许对于目的地是本机邮件就不需要了?

一点点看法,不知对错,大伙儿批一批?
 
网上copy的两篇文章,可能有用。 我没做过, 自己去试吧。
学东西很多时候是要自己去尝试的, 别人的帮助总是有限的。
其实前面的大侠们说得都没错,你不要别的smtp服务器,就得
自己作一个,呵呵,而且要去分析MX。


-------------------------------------
如何编写SMTP邮件服务器

2000年10月17日 转载自


作者:Riceball(teditor@mailroom.com)



许多时候,我想不通为什么不能直接将信件送到对方(POP或IMAP)服务器上,为什么非要通过一个莫名其妙的SMTP邮件服务器转交一次,实在不服气,如果使用UNIX,这个问题就很好解决,用sendmail就能完成递送任务,但在Windows下呢?同样的,一定也有办法饶开SMTP Server直接递送到对方的远程邮局服务器上,难得住别人,难得住我们程序员吗?分析相关协议(RFC2645,RFC821, RFC1846,RFC1939,RFC1725,RFC1730-RFC1733 etc.),我们会知道要完成直接递送其实相当简单。

首先我们看一下Email的递送过程:Email(Encode) -> a SMTP Relay Server -> Remote SMTP Server(远程邮局)。非常简单,邮件编码后被递送到一个SMTP转交服务器上,该服务器对信件分检(到同一邮局的被放在一起)后,根据优先级以及信件的先后次序被发送到远程邮局的SMTP服务器上。换句话说,只要我们知道了SMTP转交服务器是如何确定远程邮局SMTP服务器的地址的,就可以轻松地将饶开SMTP Relay Server直接递送到远程邮局服务器。

SMTP Relay Server是如何确定远程邮局服务器的地址的呢?如果你熟悉域名解析,就知道是怎么回事了,我们知道电子邮件的地址由两部分构成postbox@address.com,邮箱(postbox)和地址(address.com),给域名服务器发送指令查询“address.com”的远程邮局服务器的地址即可找到远程邮局SMTP服务器的IP 地址,该指令查询是被称作MX(Mail Exchange)邮件交换服务器的地址查询。远程邮局SMTP服务器的地址可能不止一个,这时,你可根据信件优先级的不同,将对应优先级的信件发到对应地址的远程邮局SMTP服务器,当然,你也可以不管三七二十一,随便选一个SMTP服务器发送,见后附“域名解析结果样例”。简单吧。这下,自己编写一个SMTP Server不难了吧!


问题:头ID是个麻烦的事,有时会产生Invalid Head ID 5811的错误。


附:域名解析结果样例


Answer List


Resource name is : sina.com

Type is : MX Class is : IN

MX Priority : 10 MX Server : mailcn.sina.com


Resource name is : sina.com

Type is : MX Class is : IN

MX Priority : 15 MX Server : mail.sina.com.cn



Authority List


Resource name is : sina.com

Type is : NS Class is : IN

Domain name is : resolver.sina.com


Resource name is : sina.com

Type is : NS Class is : IN

Domain name is : ns2.sina.com



Additional Response List


Resource name is : mailcn.sina.com

Type is : A Class is : IN

IP Address is : 202.106.184.233


Resource name is : mail.sina.com.cn

Type is : A Class is : IN

IP Address is : 202.106.187.150


Resource name is : resolver.sina.com

Type is : A Class is : IN

IP Address is : 206.204.114.135


Resource name is : ns2.sina.com

Type is : A Class is : IN

IP Address is : 209.133.24.135
-----------------------------------------------------------------
Email 服务器的简单实现

返回

我们知道从Delphi 3 开始,它自带的控件中有基于Internet开发的控件。如果我们充分利用这些控件开发Internet程序则可以简化编程工作,提高效率。鉴于目前POP3客户端的软件的种类繁多,(如Outlook Express,Foxmail 以及Web 方式下的各免费邮局),而服务器端(除Unix Email系统)很少公开原代码,下面我就向大家着重介绍一下利用 Delphi 4中Internet控件组的TClientSocket 和TServerSocket 控件来实现 Email POP3服务器端。如果您理解了Email POP3服务器的构造,相信也可以依葫芦画瓢写出Email SMTP服务器程序。在此基础上加入多线程技术使服务器能同时处理多个客户的连接请求,您就可以轻松地实现一个简单的Email服务器了。

---- 一. 设计思路

---- 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;
---- 三. 结语

---- 由于Email系统与数据库表结构的紧密联系,笔者没有写出各POP3命令的具体实现。相信读者在认真阅读了RFC1939之后不难写出实现函数。现在就动手为你的公司写一个自己的Email服务器吧!

返回



 
----------------------以下文章可能对你有好处-------------

“邮件特快专递”这个词现在已经是被广大的网民所熟知了,它就好比是网络上的EMS,能
够直接把邮件送到对方的邮箱中,邮件发送完毕后,对方就可以立刻收到。Foxmail在其
最新的4.0版本中也特别新增了该功能,作为一名编程爱好者,你是不是也想知道如何编程
实现该功能呢?那就随本文一起揭开“邮件特快专递”的神秘面纱:
一、实现原理
在Outlook Express中,可通过查看邮件的属性得到该邮件的头部资料。我们拿一封不是特快专递的普通邮件来进行剖析,下面是笔者一封邮件的头部资料:

Received: from sm1.163.com([202.108.44.203]) by peoplemail.com.cn(JetMail 2.5.3.0)
with SMTP id jm1ac3c063eec; Thu, 29 Nov 2001 07:20:25 -0000
Received: from xubo (unknown [61.154.94.146])
by sm1.163.com (Postfix) with ESMTP id 99CF11C461061
for <cxubo@peoplemail.com.cn>; Thu, 29 Nov 2001 15:12:49 +0800 (CST)
……
从该头部资料可以看出,邮件传递的路线是由xubo→sm1.163.com→peoplemail.com.cn,其
中xubo是本人所在机器,邮件是经由sm1.163.com这个中转站才送到目的地的,而我们平常
所说的邮件特快专递,就是把邮件直接送到目的地而不需要中转站。
如何才能知道目的地的地址呢?我们知道电子邮件的地址由用户名(username)和邮箱域
名(address.com)两部分构成的,给域名服务器发送针对“address.com”的MX指令查询
即可找到目的地的地址。被查出来的目的地可能不止一个,有时这些目的地是有优先级别
之分的,分别对应着邮件的优先级别,你可以根据邮件优先级的不同对应发送,也可以任
意选择其中一个发送,本文的示例将选择反馈回来的第一个目的地发送,读者可根据实际
需要进行改进。

二、用到的核心组件
本文将采用Indy控件集进行域名查询、邮件发送部分的编程。INDY的全名是Internet
Direct(也叫Winshoes),是一套开放源代码、跨平台、优秀的Internet控件集,它支持
大部分流行的Internet协议。Delphi 6已经包含了该控件集,如果你使用的是Delphi 6以
前的版本,请先到Indy主页http://www.nevrona.com/Indy/Download.html下载并安装该
控件集。

三、窗口设计
向窗体上放置三个TEdit组件,一个TMemo组件,四个Tlabel组件,用到的Indy组件为
TIdDNSResolver、TIdAntiFreeze、TIdSMTP、TIdMessage。其中TIdDNSResolver是用来向
域名服务器发出查询请求并得到结果,TIdMessage用来构建邮件,TIdSMTP用来发送邮件,
TidAntiFreeze可以确保Indy在工作时程序能响应来自外界的消息(注:Indy是以同步的方
式进行工作的,在读或写操作完成之前,其它代码无法执行,加入TidAntiFreeze可以在
每隔一段时间通过呼叫Application.ProcessMessage方法响应来自外界的消息。)
程序的界面如下图所示(箭头所指向的文字标识了该组件的名字):

四、程序代码(代码中包含了详细的说明)

……(前面一部分省略)
type
TForm1 = class(TForm)
IdDNSResolver: TIdDNSResolver;
IdAntiFreeze1: TIdAntiFreeze;
btnSend: TButton;
IdSMTP: TIdSMTP;
IdMsgSend: TIdMessage;
mmContent: TMemo;
Label1: TLabel;
edtTo: TEdit;
Label4: TLabel;
Label5: TLabel;
edtFrom: TEdit;
Label6: TLabel;
edtSubject: TEdit;
procedure btnSendClick(Sender: TObject);
private
{ Private declarations }
procedure GetMxList(AMxList: TStringList; AQName: string);
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

{ TForm1 }

{ 这个过程是用来得到邮件特快专递目的地服务器名称及优先级别数,参数AMXList是
用来接收结果值,AQName代表传递过来的域名 }
procedure TForm1.GetMxList(AMxList: TStringList; AQName: string);
var
i: Integer;
begin
with IdDNSResolver do
begin
Host := '202.101.107.55'; { Host属性用来指定域名服务器的地址,此处为笔者所在地
的主域名服务器地址,你也可以指定任一可以快速访问到的Internet上域名服务器
地址,要知道自己所在地的域名服务器地址,win98下通过winipcfg命令,win2000下
通过ipconfig /all即可查出。}
ReceiveTimeout := 10000; // 在指定的时间内得不到域名服务器的反馈,则视为失败。
ClearVars; // 清除前一次查询所反馈回来的资源记录

{ 构建此次查询的头部结构 }
with DNSHeader do
begin
Qr := False; // False 代表查询
Opcode := 0; // 0代表标准域名查询
RD := True; //域名服务器可以进行递归查询
QDCount := 1; //查询的数量
end;

{ 构建要查询的问题 }
DNSQDList.Clear;
with DNSQDList.Add do
begin
QName := AQName; //要查询的域名
QType := cMX; //QTYPE指定要查询的资源记录的种类,值为cMX代表邮件交换记录
QClass := cIN;
end;

ResolveDNS; //向域名服务器发出请求

{ 从域名服务器接收反馈的结果,将反馈回来的邮件服务器名称放在AMXList列表的Name
部分,
邮件服务器的优先级别数放在Value部分。 }
for i := 0 to DNSAnList.Count - 1 do
AMxList.Add(DNSAnList.RData.MX.Exchange + '=' +
IntToStr(DNSAnList.RData.MX.Preference));
end;
end;

{ 单击"发送"按钮时发送专递邮件 }
procedure TForm1.btnSendClick(Sender: TObject);
var
MxList: TStringList;
i: Integer;
QName, ThoughAddress: string;
begin
{ 根据用户所填写的内容创建邮件 }
with IdMsgSend do
begin
Body.Assign(mmContent.Lines); //邮件正文
From.Address := Trim(edtFrom.Text); //发件人地址
Recipients.EMailAddresses := Trim(edtTo.Text); //收件人地址
Subject := edtSubject.Text; //邮件主题
end;

{ 从输入的收件人地址中取出邮箱域名,利用前面的GetMxList过程得到目的地地址 }
QName := TrimRight(copy(edtTo.Text, Pos('@', edtTo.Text) + 1, Length(edtTo.Text)));
MxList := TStringList.Create;
try
GetMxList(MxList, QName);
ThoughAddress := MxList.Names[0]; {取反馈回来的第一个服务器为目的地,读者可
根据实际需要改进,比如说考虑到信件的优先级或当你选择的服务器因繁忙而暂时
不能处理你的信件时,换用其它服务器试试 }
finally
MxList.Free;
end;

{ 发送邮件 }
with IdSMTP do
begin
Host := ThoughAddress; // 将Host赋值为目的地,这就是特快专递与普通邮件的区别
Port := 25; // smtp服务默认的端口为25
Connect; //连接到服务器
try
Send(IdMsgSend); //发送刚才创建的邮件
ShowMessage('发送完毕'); //发送完毕后提示
finally
Disconnect; //断开服务器连接
end;
end;
end;

end.

本程序在Windows 2000 + Delphi 6 下调试通过,点击这里下载。
http://www.ccw.com.cn/htm/app/down/1204Source.zip
 
所谓的邮件特快专题根本就没用,反正我用indy的例子或者按照上面文章的例子
发送給163.com都是没用的
 
上面的例子存在一个同步的问题其实很简单,必须加一个application.processmessage就可以了
 
to: dyydyy
存在一个同步的问题?----什么意思?
application.processmessage-----在那里加?
 
[red]请问IdMessage创建邮件的时候如何添加附件,非常急!知道请告诉enigma0702@hotmail.com,万分感谢![/red]
 
其实要写一个邮件服务器很简单的,只要有一个DNS用WinSock再看看有关的协议文档
就可以搞定了不过这里有一个问题就是密码的问题,在验证用户身份的时候有一个
密码是明文还是密文的问题,我想这可能要涉及到密码学的加密与解密了。我在前阵
子写了一个邮件服务器,只是没有密码及数据的加密但是用起来还是没有什么问题的,
如果哪位大虾有兴趣可以一起来探讨这个问题啊
:)
 
份太少了?
 
分确实太少了,主要重点都在Feizi所贴的内容中,本人曾结合几个方面的问题,做了
一个快捷发送电子邮件的程序,不用填写smtp等相关内容,还可以发送附带附件内容的
邮件。只不过附件内容不可大于500k(是否是indy的问题?),不知为何?谁能解决,
本人奉上全部源程序。
 
发送邮件不但是使用了SMTP的功能,同时还需要RELAY的功能,也就是说需要邮件转发的功能,
不然的话,你通过163.com发送邮件到hotmail.com的邮件就不可能发出,邮件特快的功能是
通过DNS服务器查找到邮件地址的SMTP服务器地址,直接把邮件发送到对方的邮件箱中,也就是
说不需要RELAY进行邮件的转发.
 
163.com 邮件直发问题,谁能解决?
 
安装一个邮件服务器在自己机器上,不就可以不通过网络的SMTP服务器了吗?如果自己写软件
那你只有自己写一个了,或者要求用户安装IIS并且配置好邮件服务器
 
FeiZi给出的实例谁发信成功了?我的为什么发送成功以后却在信箱里面没有?
 
通过DNS解析163.com的MX地址可以得到如下的地址
m180.163.com
m207.163.com
m208.163.com
...
然后选择其中一个进行IP地址的转换
如:m207.163.com对应于202.108.44.207
这样你可以通过telnet 202.108.44.207 25
用命令方式把邮件发送到163.com的邮件地址中。
或者把邮件客户端的SMTP服务器地址设置为此IP地址,就可以不通过认证直接发送到
以163.com结尾的任何邮件地址.
我写了一个最终进行地址->IP地址转换的程序例子
下载:http://infocaptor.3322.net/dns.rar
 
后退
顶部