SoonMail.pas
上传用户:bjzs88
上传日期:2013-03-31
资源大小:3k
文件大小:10k
源码类别:

网络编程

开发平台:

Pascal

  1. {
  2. Send Posthaste_Email Unit
  3. Author   : FI7KE
  4. HomePage : http://www.fi7ke.com
  5. Usage    : SendMail('Fi7ke@Wrsky.com', Sebooks@163.com, 'Subject', 'Mail Text...');
  6. }
  7. unit SoonMail;
  8. interface
  9. uses WinSock;
  10. procedure SendMail(MyEmail, ToMail, subject, Content: string);
  11. implementation
  12. const
  13.   EOF = #13#10;
  14. var
  15.   WSAData: TWSAData;
  16. type
  17.   TIPAddressString = array[0..4 * 4 - 1] of Char; //用来放IP的
  18.   PIPAddrString = ^TIPAddrString;
  19.   TIPAddrString = record
  20.     Next: PIPAddrString;
  21.     IPAddress: TIPAddressString;
  22.     IPMask: TIPAddressString;
  23.     Context: Integer;
  24.   end;
  25.   PFixedInfo = ^TFixedInfo;
  26.   TFixedInfo = record
  27.     FI7KE: array[0..262] of Char; //纯粹占位用的
  28.     CurrentDNSServer: PIPAddrString;
  29.     DNSServerList: TIPAddrString;
  30.   end;
  31.   PMXQuery = ^MXQuery;
  32.   MXQuery = record
  33.     ID: WORD;
  34.     Flag: WORD;
  35.     Question: WORD;
  36.     Answer: WORD;
  37.     Author: WORD;
  38.     Addition: WORD;
  39.     secB: BYTE;
  40.     secE: BYTE;
  41.     FType: WORD;
  42.     Fclass: WORD;
  43.   end;
  44.   ip_mreq = record
  45.     imr_multiaddr: in_addr;
  46.     imr_interface: in_addr;
  47.   end;
  48.   TIpMReq = ip_mreq;
  49.   PIpMReq = ^ip_mreq;
  50.   TClientSocket = class(TObject)
  51.   protected
  52.     FSocket: TSocket;
  53.   public
  54.     procedure Connect(Address: string);
  55.     procedure Disconnect;
  56.     function SendBuffer(Buffer: string): integer;
  57.     function ReceiveBuffer: integer;
  58.   end;
  59. function GetNetworkParams(FI: PFixedInfo; var BufLen: Integer): Integer;
  60.   stdcall; external 'iphlpapi.dll' Name 'GetNetworkParams';
  61. function CharUpper(lpsz: PChar): PChar; stdcall external 'user32.dll' Name 'CharUpperA';
  62. function StrToInt(cStr: string): Longint;
  63. var
  64.   Code: Integer;
  65. begin
  66.   val(cStr, Result, Code);
  67. end;
  68. function IntToHex(N: LongWord; Digits: Cardinal): string;
  69. asm
  70.         PUSH    ESI
  71.         PUSH    EDI
  72.         PUSH    EBX
  73.         MOV     ESI,EAX
  74.         MOV     EDI,ECX
  75.         MOV     EBX,EDX
  76.         MOV     EAX,ECX
  77.         MOV     ECX,EDX
  78.         XOR     EDX,EDX
  79.         CALL    System.@LStrFromPCharLen
  80.         MOV     EAX,ESI
  81.         MOV     ESI,[EDI]
  82.         MOV     EDI,ESI
  83. @@lp1:  DEC     EBX
  84.         JS      @@lp2
  85.         MOV     DL,AL
  86.         AND     DL,$0F
  87.         CMP     DL,$09
  88.         JA      @@bd
  89.         ADD     DL,$30
  90.         MOV     BYTE PTR [ESI],DL
  91.         INC     ESI
  92.         SHR     EAX,4
  93.         JNE     @@lp1
  94.         JMP     @@bl
  95. @@bd:   ADD     DL,$37
  96.         MOV     BYTE PTR [ESI],DL
  97.         INC     ESI
  98.         SHR     EAX,4
  99.         JNE     @@lp1
  100. @@bl:   DEC     EBX
  101.         JS      @@lp2
  102.         MOV     BYTE PTR [ESI],$30
  103.         INC     ESI
  104.         JMP     @@bl
  105. @@lp2:  DEC     ESI
  106.         CMP     EDI,ESI
  107.         JAE     @@qt
  108.         MOV     AH,BYTE PTR [EDI]
  109.         MOV     AL,BYTE PTR [ESI]
  110.         MOV     BYTE PTR [ESI],AH
  111.         MOV     BYTE PTR [EDI],AL
  112.         INC     EDI
  113.         JMP     @@lp2
  114. @@qt:   POP     EBX
  115.         POP     EDI
  116.         POP     ESI
  117. end;
  118. function StrToHex(const Value: string; By: Integer): string;
  119. var
  120.   i, Index: Integer;
  121. begin
  122.   Result := '';
  123.   for i := 1 to Length(Value) do
  124.   begin
  125.     Index := Ord(Value[i]);
  126.     Result := Result + IntToHex(Index, By);
  127.   end;
  128. end;
  129. function StrCopy(Dest: PChar; const Source: PChar): PChar; assembler; //Str To array
  130. asm
  131.         PUSH    EDI
  132.         PUSH    ESI
  133.         MOV     ESI,EAX
  134.         MOV     EDI,EDX
  135.         MOV     ECX,0FFFFFFFFH
  136.         XOR     AL,AL
  137.         REPNE   SCASB
  138.         NOT     ECX
  139.         MOV     EDI,ESI
  140.         MOV     ESI,EDX
  141.         MOV     EDX,ECX
  142.         MOV     EAX,EDI
  143.         SHR     ECX,2
  144.         REP     MOVSD
  145.         MOV     ECX,EDX
  146.         AND     ECX,3
  147.         REP     MOVSB
  148.         POP     ESI
  149.         POP     EDI
  150. end;
  151. function StrLen(const Str: PChar): Cardinal; assembler; //取数据包长度
  152. asm
  153.         MOV     EDX,EDI
  154.         MOV     EDI,EAX
  155.         MOV     ECX,0FFFFFFFFH
  156.         XOR     AL,AL
  157.         REPNE   SCASB
  158.         MOV     EAX,0FFFFFFFEH
  159.         SUB     EAX,ECX
  160.         MOV     EDI,EDX
  161. end;
  162. function UpperCase(const S: string): string;
  163. begin
  164.   Result := CharUpper(Pchar(S));
  165. end;
  166. function AllocMem(Size: Cardinal): Pointer;
  167. begin
  168.   GetMem(Result, Size);
  169.   FillChar(Result^, Size, 0);
  170. end;
  171. function GetDNSAddress: string; //获取本地DNS
  172. var
  173.   FI: PFixedInfo;
  174.   Size: Integer;
  175.   DNS: PIPAddrString;
  176. begin
  177.   Size := 1024;
  178.   GetMem(FI, Size);
  179.   if GetNetworkParams(FI, Size) <> 0 then
  180.   begin
  181.     Result := 'FI7KE';
  182.     Exit;
  183.   end
  184.   else
  185.   begin
  186.     DNS := @FI^.DNSServerList;
  187.     Result := DNS^.IPAddress;
  188.   end;
  189.   FreeMem(FI);
  190. end;
  191. procedure CreateQuery(MyQuery: PMXQuery; sAddr: string); //构造UDP查询包
  192. var
  193.   pData, pTemp: PChar;
  194.   Len, I: Integer;
  195.   Pof: PWord;
  196. begin
  197.   FillChar(MyQuery^, sizeof(MXQuery) + Length(sAddr), 0);
  198.   MyQuery^.ID := $781;
  199.   MyQuery^.Flag := $1; //标准查询
  200.   MyQuery^.Question := $100;
  201.   MyQuery^.Answer := $0;
  202.   MyQuery^.Author := $0;
  203.   MyQuery^.Addition := $0;
  204.   Len := Length(sAddr) + 2;
  205.   pData := AllocMem(Len);
  206.   Inc(pData);
  207.   Move(sAddr[1], pData^, Length(sAddr));
  208.   Dec(pData);
  209.   pTemp := pData;
  210.   I := Pos('.', sAddr);
  211.   while I > 0 do
  212.   begin
  213.     pTemp^ := Chr(I - 1);
  214.     Inc(pTemp, I);
  215.     Delete(sAddr, 1, i);
  216.     I := Pos('.', sAddr);
  217.   end;
  218.   
  219.   pTemp^ := Chr(Length(sAddr));
  220.   Inc(pTemp, Length(sAddr) + 1);
  221.   pTemp^ := #0;
  222.   pTemp := @MyQuery^.secB;
  223.   Move(pData^, pTemp^, Len);
  224.   FreeMem(pData);
  225.   Pof := PWord(pTemp + Len);
  226.   Pof^ := htons($0F);
  227.   Inc(pof);
  228.   Pof^ := htons(1);
  229. end;
  230. function PickPack(pbuf: PChar): string; //处理返回的UDP包
  231. var
  232.   p: PChar;
  233.   I, N: Integer;
  234.   Temp: string;
  235. begin
  236.   p := pbuf;
  237.   INC(P, 11);
  238.   while StrToHex(string(P[1]), 1) <> '0' do
  239.   begin
  240.     N := StrToInt(StrToHex(string(P[1]), 1));
  241.     Temp := Temp + '.';
  242.     for I := 1 to N do
  243.     begin
  244.       INC(P);
  245.       Temp := Temp + string(P[1]);
  246.     end;
  247.     INC(P);
  248.   end;
  249.   if POS('GMAIL.COM', UpperCase(Temp)) > 0 then //Gmail的返回信息与其它的有些不同,懒得深入了,将就一下
  250.   begin
  251.     Result := 'gsmtp185.google.com';
  252.     Exit;
  253.   end;
  254.   INC(P, 19);
  255.   while StrToHex(string(P[1]), 2) <> 'C0' do
  256.   begin
  257.     N := StrToInt(StrToHex(string(P[1]), 1));
  258.     if N = 0 then
  259.     begin
  260.       Result := Result;
  261.       Exit;
  262.     end;
  263.     Result := Result + '.';
  264.     for I := 1 to N do
  265.     begin
  266.       INC(P, 1);
  267.       Result := Result + string(P[1]);
  268.     end;
  269.     INC(P);
  270.   end;
  271.   Result := Result + Temp;
  272. end;
  273. function GetEMailServer(EMailServer: string): string; //获取目标服务器IP
  274. var
  275.   wsa: TWSAData;
  276.   sock: TSocket;
  277.   remote: TSockAddr;
  278.   mcast: ip_mreq;
  279.   buffer: array[1..4096] of Char;
  280.   Len: integer;
  281.   I: Integer;
  282.   Query: PMXQuery;
  283.   Temp: string;
  284. begin
  285.   if GetDNSAddress <> 'FI7KE' then
  286.   begin
  287.     WSAStartup($0202, wsa);
  288.     sock := socket(AF_INET, SOCK_DGRAM, 0);
  289.     remote.sin_family := AF_INET;
  290.     remote.sin_port := htons(53);
  291.     remote.sin_addr.S_addr := inet_addr(PChar(GetDNSAddress));
  292.     Query := AllocMem(sizeof(MXQuery) + Length(EMailServer));
  293.     CreateQuery(Query, EMailServer);
  294.     sendto(sock, Query^, SizeOf(MXQuery) + Length(EMailServer), 0, remote, sizeof(remote));
  295.     I := SizeOf(Remote);
  296.     Len := RecvFrom(Sock, buffer, sizeof(buffer), 0, Remote, I);
  297.     Temp := PickPack(@Buffer);
  298.     if Temp[1] = '.' then
  299.       Temp := Copy(Temp, 2, Length(Temp));
  300.     Result := Temp;
  301.   end
  302.   else
  303.     Result := 'FI7KE';
  304.   closesocket(sock);
  305.   WSACleanup;
  306. end;
  307. procedure TClientSocket.Connect(Address: string); //连接目标邮件服务器
  308. var
  309.   SockAddrIn: TSockAddrIn;
  310.   HostEnt: PHostEnt;
  311. begin
  312.   Disconnect;
  313.   FSocket := Winsock.socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  314.   SockAddrIn.sin_family := AF_INET;
  315.   SockAddrIn.sin_port := htons(25);
  316.   SockAddrIn.sin_addr.s_addr := inet_addr(PChar(Address));
  317.   if SockAddrIn.sin_addr.s_addr = INADDR_NONE then
  318.   begin
  319.     HostEnt := Gethostbyname(PChar(Address));
  320.     if HostEnt = nil then
  321.     begin
  322.       Exit;
  323.     end;
  324.     SockAddrIn.sin_addr.s_addr := Longint(PLongint(HostEnt^.h_addr_list^)^);
  325.   end;
  326.   Winsock.Connect(FSocket, SockAddrIn, SizeOf(SockAddrIn));
  327. end;
  328. procedure TClientSocket.Disconnect; //关闭套字节
  329. begin
  330.   Closesocket(FSocket);
  331. end;
  332. function TClientSocket.SendBuffer(Buffer: string): integer; //发送数据
  333. var
  334.   Buf: array[0..1024] of char;
  335. begin
  336.   StrCopy(Buf, PChar(Buffer));
  337.   Result := send(FSocket, Buf, StrLen(Buf), 0);
  338.   if Result = SOCKET_ERROR then
  339.   begin
  340.     if (WSAGetLastError = WSAEWOULDBLOCK) then
  341.     begin
  342.       Result := -1;
  343.     end
  344.     else
  345.     begin
  346.       Disconnect;
  347.     end;
  348.   end;
  349. end;
  350. function TClientSocket.ReceiveBuffer: integer; //接收数据
  351. var
  352.   Buf: array[0..1024] of char;
  353. begin
  354.   Result := recv(FSocket, Buf, 1025, 0);
  355. end;
  356. procedure SendMail(MyEmail, ToMail, subject, Content: string); //投递邮件
  357. var
  358.   MySock: TClientSocket;
  359. begin
  360.   MySock := TClientSocket.Create;
  361.   MySock.Connect(GetEmailServer(Copy(Tomail, pos('@', Tomail) + 1, LengTh(Tomail))));
  362.   MySock.ReceiveBuffer;
  363.   MySock.SendBuffer('HELO FI7KE' + EOF);
  364.   MySock.ReceiveBuffer;
  365.   MySock.SendBuffer('MAIL FROM:<' + MyEmail + '>' + EOF);
  366.   MySock.ReceiveBuffer;
  367.   MySock.SendBuffer('RCPT TO:<' + TOMail + '>' + EOF);
  368.   MySock.ReceiveBuffer;
  369.   MySock.SendBuffer('DATA' + EOF);
  370.   MySock.ReceiveBuffer;
  371.   MySock.SendBuffer
  372.     (
  373.     'FROM:<' + MyEmail + '>' + EOF +
  374.     'TO:<' + ToMail + '>' + EOF +
  375.     'SUBJECT:' + Subject + EOF + EOF +
  376.     Content + EOF +
  377.     '.' + EOF
  378.     );
  379.   MySock.ReceiveBuffer;
  380.   MySock.SendBuffer('QUIT' + EOF);
  381.   MySock.ReceiveBuffer;
  382.   MySock.Disconnect;
  383. end;
  384. initialization
  385.   WSAStartUp($0202, WSAData);
  386. finalization
  387.   WSACleanup;
  388. end.