不想用Delphi的Indy控件. 实在是BUG太多, 而且引用后,你的程序容量将大量增加
在考虑之后决定使用纯winsock来写一个发邮件的类, 并且支持发送附件.
在网上找到smtp协议介绍.,并且自己用foxmail发送一封带附件的邮件
抓包分析后 写了一个发送邮件的类. 可能有些BUG 请大家指出
调用方法
uses uMail; var Mail : TMail; begin Mail := TMail.Create; try Mail.Host := 'alin.vicp.cc'; Mail.FromAddr := 'test@alin.vicp.cc' ; Mail.Password := '111111'; Mail.ToAddr := 'test@alin.vicp.cc' ; Mail.Subject := '测试发送的邮件!'; Mail.Body := '这是一封测试的邮件!'; Mail.Attaches.Add('c:\test.rar'); Mail.Attaches.Add('c:\test1.rar'); if Mail.Send then ShowMessage('Send Ok') else ShowMessage('Send Failed' + #13 + Mail.ErrMsg); finally Mail.Free; end; end;
unit uMail; interface uses WinSock, Windows, SysUtils, Classes, Math; const CRLF :string = #13 + #10; type TMail = class private FFromAddr : string; FToAddr : string; FSubject : string; FBody : string; FErrMsg : string; FHost : string; FAttaches : TStrings; FSendData : TStrings; FPassword : string; function chunklenSplit(Value : string): string; function GetSendData: string; protected procedure InitSendData; public constructor Create; destructor Destory; property Host : string read FHost write FHost; //主机名 property FromAddr : string read FFromAddr write FFromAddr; //来自 property ToAddr : string read FToAddr write FToAddr;//发送到 property Subject : string read FSubject write FSubject;//标题 property Body : string read FBody write FBody;//内容 property Attaches : TStrings read FAttaches write FAttaches;//附件 property ErrMsg : string read FErrMsg;//错误信息 property SendData : string read GetSendData;//邮件发送的详细内容 property Password : string read FPassword write FPassword;//密码 function Send : boolean; end; implementation uses Base64; { TMail } function TMail.chunklenSplit(Value: string): string; var I,len : integer; begin Result := ''; for i := 0 to floor(Length(Value) / 76) do begin if i * 76 + 77 > Length(Value) then len := Length(Value) - (i-1) * 76 + 1 else len := 76; Result := Result + Copy(Value,i * 76 + 1,len) + CRLF; end; end; constructor TMail.Create; var WSData: TWSAData; begin WSAstartup(1, WSData); FAttaches := TStringList.Create; FSendData := TStringList.Create; end; destructor TMail.Destory; begin FAttaches.Free; FSendData.Free; WSACleanup; end; function TMail.GetSendData: string; begin Result := FSendData.Text; end; procedure TMail.InitSendData; var guid : TGUID; fs : TFileStream; fbuf : array of byte; boundary,fn,sbuf : string; i : integer; begin FSendData.Clear; CreateGUID(guid); boundary := Copy(GuidToString(Guid),2,Length(GuidToString(Guid))-2); FSendData.Add('From: "'+FFromAddr+'" <'+FFromAddr+'>'); FSendData.Add('To: "'+FToAddr+'"'); FSendData.Add('Subject: '+ FSubject); FSendData.Add('MIME-Version: 1.0'); FSendData.Add('Content-Type: multipart/mixed;'); FSendData.Add(#9 + 'boundary="=='+boundary+'"' + CRLF); FSendData.Add('This is a MIME encoded message.' + CRLF); FSendData.Add('--=='+boundary); FSendData.Add('Content-Type: text/plain;'); FSendData.Add(#9+'charset="gb2312"'); FSendData.Add('Content-Transfer-Encoding: base64'+ CRLF); FSendData.Add(Base64EncodeStr(FBody) + CRLF); for i := 0 to FAttaches.Count - 1 do begin if FileExists(FAttaches[i]) then begin fn := ExtractFileName(FAttaches[i]); FSendData.Add('--==' + boundary); FSendData.Add('Content-Type: application/octet-stream;'); FSendData.Add(#9 + 'name="'+fn+'"'); FSendData.Add('Content-Transfer-Encoding: base64'); FSendData.Add('Content-Disposition: attachment;'); FSendData.Add(#9+'filename="'+fn+'"' + CRLF); fs := TFileStream.Create(FAttaches[i], fmShareDenyNone); try SetLength(fbuf,fs.Size); SetLength(sbuf, ((fs.Size+2) div 3)*4); fs.ReadBuffer(fbuf[0], fs.Size); Base64Encode(fbuf,@sbuf[1],fs.Size); sbuf := chunklenSplit(sbuf); FSendData.Add(sbuf); finally fs.Free; end; end; end; FSendData.Add('--=='+boundary+'--' + CRLF + CRLF + '.'); end; function TMail.Send: boolean; var sock : TSocket; mhost : PHostEnt; maddr : TSockAddrIn; rbuf : array[0..255] of char; sbuf : string; begin Result := true; sock := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); try if sock = INVALID_SOCKET then begin Result := false; FErrMsg := '创建Socket失败!'; Exit; end; mhost := gethostbyname(pchar(FHost)); if mhost = nil then begin Result := false; FErrMsg := '获取主机地址失败!'; Exit; end; maddr.sin_family := AF_INET; maddr.sin_port := htons(25); maddr.sin_addr.S_addr := Longint(PLongint(mhost^.h_addr_list^)^);; if connect(sock,maddr, sizeof(maddr)) < 0 then begin Result := false; FErrMsg := '链接主机失败!'; Exit; end; recv(sock, rbuf, sizeof(rbuf),0); //链接成功 if rbuf[0] <> '2' then begin Result := false; FErrMsg := rbuf; Exit; end; //服务器标识 sbuf := 'EHLO '+ IntToStr(GetCurrentThreadID) + CRLF; winsock.send(sock, sbuf[1], Length(sbuf),0); recv(sock, rbuf, sizeof(rbuf),0); if rbuf[0] <> '2' then begin Result := false; FErrMsg := rbuf; Exit; end; //请求验证 sbuf := 'AUTH LOGIN'+ CRLF; winsock.send(sock, sbuf[1], Length(sbuf),0); recv(sock, rbuf, sizeof(rbuf),0); if rbuf[0] <> '3' then begin Result := false; FErrMsg := rbuf; Exit; end; //发送用户名 sbuf := Base64EncodeStr(FFromAddr)+ CRLF; winsock.send(sock, sbuf[1], Length(sbuf),0); recv(sock, rbuf, sizeof(rbuf),0); if rbuf[0] <> '3' then begin Result := false; FErrMsg := rbuf; Exit; end; //发送密码 sbuf := Base64EncodeStr(FPassword)+ CRLF; winsock.send(sock, sbuf[1], Length(sbuf),0); recv(sock, rbuf, sizeof(rbuf),0); if rbuf[0] <> '2' then begin Result := false; FErrMsg := rbuf; Exit; end; //来自 sbuf := 'MAIL FROM: <'+ FFromAddr +'>'+ CRLF; winsock.send(sock, sbuf[1], Length(sbuf),0); recv(sock, rbuf, sizeof(rbuf),0); if rbuf[0] <> '2' then begin Result := false; FErrMsg := rbuf; Exit; end; //发送到 sbuf := 'RCPT TO: <'+ FToAddr +'>'+ CRLF; winsock.send(sock, sbuf[1], Length(sbuf),0); recv(sock, rbuf, sizeof(rbuf),0); if rbuf[0] <> '2' then begin Result := false; FErrMsg := rbuf; Exit; end; //准备发送数据 sbuf := 'DATA'+ CRLF; winsock.send(sock, sbuf[1], Length(sbuf),0); recv(sock, rbuf, sizeof(rbuf),0); if (rbuf[0] <> '3') or (rbuf[1] <> '5') then begin Result := false; FErrMsg := rbuf; Exit; end; //初始化需要发送的数据 InitSendData; sbuf := FSendData.Text; winsock.send(sock, sbuf[1], Length(sbuf),0); recv(sock, rbuf, sizeof(rbuf),0); if rbuf[0] <> '2' then begin Result := false; FErrMsg := rbuf; Exit; end; sbuf := 'QUIT' + CRLF ; winsock.send(sock, sbuf[1], Length(sbuf),0); recv(sock, rbuf, sizeof(rbuf),0); finally CloseSocket(sock); end; end; end.
——————————————————————————–
【版权声明】: 本文原创于http://2Lin.net, 转载请注明作者并保持文章的完整, 谢谢!
通不过服务器的验证亚![s:2]
你用的是什么邮箱
建议使用foxmail的
因为我用foxmail测试通过
163的好像无法发送。
你好,你的这个程序是可以通过验证的,我编译测试了!
163不能发的,因为163是默认关闭SMTP的,你需要升级才能使用!
[s:1]
我支持你,收我为徒吧