Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Сети > Помогите с отправкой e-mail


Автор: denks 17.4.2006, 12:38
Помогите с отправкой e-mail . Не пойму в чём дело. Пытаюсь отослать на ящик на mail.ru. Примерно из 20 ящиков, сообщения доходят только на один. Вот полный код. Заранее спасибо.
--------------------------------------------------------------------------------------

Код

unit mail;

interface

uses
  Windows, WinSock;

const
  CRLF = #13#10;

  CSMTPCommands: array[0..20, 0..1] of String = (
    ('211', 'System status, or system help reply'),
    ('214', 'Help message'),
    ('220', 'Service ready'),
    ('221', 'Service closing transmission channel'),
    ('250', 'Requested mail action okay, completed'),
    ('251', 'User not local'),
    ('354', 'Start mail input'),
    ('421', 'Service not available, closing transmission channel'),
    ('450', 'Requested mail action not taken: mailbox unavailable'),
    ('451', 'Requested action aborted: local error in processing'),
    ('452', 'Requested action not taken: insufficient system storage'),
    ('500', 'Syntax error, command unrecognized'),
    ('501', 'Syntax error in parameters or arguments'),
    ('502', 'Command not implemented'),
    ('503', 'Bad sequence of commands'),
    ('504', 'Command parameter not implemented'),
    ('550', 'Requested action not taken: mailbox unavailable'),
    ('551', 'User not local'),
    ('552', 'Requested mail action aborted: exceeded storage allocation'),
    ('553', 'Requested action not taken: mailbox name not allowed'),
    ('554', 'Transaction failed')
  );

  {SMTP Error Codes}
  ERR_NOERROR = 0;
  ERR_SMTP_MALFORMED = 1;
  ERR_SMTP_UNK_COMMAND = 2;
  ERR_ONCMD_STR = 3;
  ERR_RECV = 4;
  ERR_SEND = 5;

type
  TTextSocket = class(TObject)
  private
    FSocket: TSocket;
  public
    function Connect(const Host: String; Port: Word): Boolean;
    procedure Disconnect;
    function ReceiveData(var Buffer: String): Boolean;
    function SendData(var Data; Len: Integer): Boolean;
  end;

  TTextProtocol = class(TTextSocket);  

  TSMTPProtocol = class(TTextProtocol)
  private
    FLastError: Integer;
    FLastErrorStr: String;
    procedure MakeStringError(const Command: String);
    
    {SEND}
    function MakeCommand(const Value: String): String;
    function MakeHello(const Host: String): String;
    function MakeMailFrom(const User: String): String;
    function MakeMailTo(const User: String): String;
    function MakeDataStart: String;
    function MakeData(const Data: String): String;
    function MakeQuit: String;
    function SendSMTPCommand(Command: String): Boolean;

    {RECV}
    function CheckIfValidCommand(const Value: String): Integer;
    function RecvSMTPCommand(var Command: String): Boolean;
  public
    function MakeSMTPSession(const Host, UserFrom, UserTo, Data: String): Boolean;
    property LastError: Integer read FLastError;
    property LastErrorStr: String read FLastErrorStr;
  end;

var
  WSAData: TWSAData;
  FWSAStarted: Boolean;

implementation

{SMTP}

function TSMTPProtocol.MakeCommand(const Value: String): String;
begin
  Result := Value + CRLF;
end;

function TSMTPProtocol.MakeHello(const Host: String): String;
begin
  Result := MakeCommand('EHLO ' + Host);
end;

function TSMTPProtocol.MakeMailFrom(const User: String): String;
begin
  Result := MakeCommand('MAIL FROM:' + User);
end;

function TSMTPProtocol.MakeMailTo(const User: String): String;
begin
  Result := MakeCommand('RCPT TO:' + User);
end;

function TSMTPProtocol.MakeDataStart: String;
begin
  Result := MakeCommand('DATA');
end;

function TSMTPProtocol.MakeData(const Data: String): String;
var f:file;
d:file;
FileBuf : AnsiString;
FileBuf1: AnsiString;
p:AnsiString;
begin
AssignFile(F,'c:\test.txt');
      FileMode:=0;
      {$I-}
      Reset(F,1);
      IF IOResult=0 THEN BEGIN
        SetLength(FileBuf,FileSize(F));
        BlockRead(F,FileBuf[1],FileSize(F));
        CloseFile(F);
        end;
        end;
  Result := MakeCommand('тест '  + CRLF + CRLF + Data + CRLF +'Content-Type: application/x-shockwave-flash;'#13#10+
             '    name="'+'тест'+'"'#13#10 +filebuf+crlf+'тест'#13#10+filebuf1+'.');
end;

function TSMTPProtocol.MakeQuit: String;
begin
  Result := MakeCommand('QUIT');
end;

function TSMTPProtocol.CheckIfValidCommand(const Value: String): Integer;
var
  Command: String;
  i: Integer;
begin
  if Length(Value) < 4 then begin
    Result := ERR_SMTP_MALFORMED;
    Exit;
  end;
  Command := Copy(Value, 0, 3);
  for i := Low(CSMTPCommands) to High(CSMTPCommands) do
    if CSMTPCommands[i, 0] = Command then begin
      Result := ERR_NOERROR;
      Exit;
    end;
  Result := ERR_SMTP_UNK_COMMAND;
  FLastErrorStr := Command;
end;

function TSMTPProtocol.RecvSMTPCommand(var Command: String): Boolean;
var
  RcvData: String;
begin
  if not ReceiveData(RcvData) then begin
    FLastError := ERR_RECV;
    Result := False;
    Exit;
  end;
  FLastError := CheckIfValidCommand(RcvData);
  Result := FLastError = ERR_NOERROR;
  if Result then
    Command := Copy(RcvData, 0, 3)
end;

function TSMTPProtocol.SendSMTPCommand(Command: String): Boolean;
begin
  {SendData}
  Result := SendData(Command[1], Length(Command));
  if not Result then
    FLastError := ERR_SEND;
end;

procedure TSMTPProtocol.MakeStringError(const Command: String);
var
  i: Integer;
begin
  for i := Low(CSMTPCommands) to High(CSMTPCommands) do
    if CSMTPCommands[i, 0] = Command then begin
      FLastError := ERR_ONCMD_STR;
      FLastErrorStr := CSMTPCommands[i, 1];
    end;
end;

function TSMTPProtocol.MakeSMTPSession(const Host, UserFrom, UserTo, Data: String): Boolean;
var
  Command: String;
begin
  Result := False;
  FLastError := ERR_NOERROR;

  {Receive Server's Greeting}
  if not RecvSMTPCommand(Command) then Exit;
  if Command <> '220' then begin
     MakeStringError(Command);
     Exit;
  end;

  {HELO}
  if not SendSMTPCommand(MakeHello('localhost')) then Exit;
  if not RecvSMTPCommand(Command) then Exit;
  if Command <> '250' then begin
     MakeStringError(Command);
     Exit;
  end;

  {MAIL FROM: user@domain.com}
  if not SendSMTPCommand(MakeMailFrom(UserFrom)) then Exit;
  if not RecvSMTPCommand(Command) then Exit;
  if Command <> '250' then begin
     MakeStringError(Command);
     Exit;
  end;

  {RCPT TO: user@domain.com}
  if not SendSMTPCommand(MakeMailTo(UserTo)) then Exit;
  if not RecvSMTPCommand(Command) then Exit;
  if Command <> '250' then begin
     MakeStringError(Command);
     Exit;
  end;

  {DATA}
  if not SendSMTPCommand(MakeDataStart) then Exit;
  if not RecvSMTPCommand(Command) then Exit;
  if Command <> '354' then begin
     MakeStringError(Command);
     Exit;
  end;

  {Message Body}
  if not SendSMTPCommand(MakeData(Data)) then Exit;
  if not RecvSMTPCommand(Command) then Exit;
  if Command <> '250' then begin
     MakeStringError(Command);
     Exit;
  end;

  {QUIT}
  if not SendSMTPCommand(MakeQuit) then Exit;

  Result := True;
end;

{ TTextSocket }

function TTextSocket.Connect(const Host: String; Port: Word): Boolean;
var
  addr: Integer;
  sockaddr: sockaddr_in;
begin
  Result := False;

  if not FWSAStarted then Exit;

  FSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if FSocket = INVALID_SOCKET then Exit;

  addr := inet_addr(PChar(Host));
  if addr = INADDR_NONE then Exit;

  sockaddr.sin_family := AF_INET;
  sockaddr.sin_port := htons(Port);
  sockaddr.sin_addr.S_addr := addr;

  Result := WinSock.connect(FSocket, sockaddr, sizeof(sockaddr)) <> SOCKET_ERROR;
end;

procedure TTextSocket.Disconnect;
begin
  if FSocket <> INVALID_SOCKET then begin
    closesocket(FSocket);
    FSocket := INVALID_SOCKET;
  end;
end;

function TTextSocket.ReceiveData(var Buffer: String): Boolean;
var
  LocBuf: array[0..1023] of Byte;
  RecvLen: Integer;

  function IsComplete: Boolean;
  begin
    Result := (Length(Buffer) > 1) and (Buffer[Length(Buffer)-1] = #13) and (Buffer[Length(Buffer)] = #10);
  end;
begin
  Buffer := '';
  Result := False;
  while True do begin
    RecvLen := recv(FSocket, LocBuf, SizeOf(LocBuf)-1, 0);
    if RecvLen = SOCKET_ERROR then
      Exit
    else if RecvLen = 0 then
      Break
    else begin
      LocBuf[RecvLen] := 0;
      Buffer := Buffer + Copy(PChar(@LocBuf), 0, RecvLen);
      if IsComplete then begin
        Result := True;
        Exit;
      end;
    end;
  end;
  Result := IsComplete;
end;

function TTextSocket.SendData(var Data; Len: Integer): Boolean;
begin
  Result := send(FSocket, Data, Len, 0) <> SOCKET_ERROR;
end;


initialization
  FWSAStarted := WSAStartup(MAKEWORD(1, 1), WSAData) = 0;

finalization
  if FWSAStarted then
    WSACleanup;

end.



------------------------------------------------------------------------------------------------------------------------
Вызываю так
--------------------------------------------
Код

function send:boolean;
var
  P: TSMTPProtocol;
begin
  P := TSMTPProtocol.Create;
  if P.Connect('194.67.23.111', 25) then begin
if P.MakeSMTPSession('194.67.23.111','test@mail.ru','test@mail.ru','тест') then
P.Disconnect;
end;
end;    
 

Автор: Matematik 18.4.2006, 09:16
Что именно не работает? Выдает ошибку? Или отправляется и не доходит? 

Автор: denks 18.4.2006, 11:18
Отправляю на mail.ru. Сообщения не доходят. Подскажите пожалуйста в чём причина. 

Автор: Matematik 18.4.2006, 11:32
Код рабочий. 
А может все таки не отправляет?
попробуй
Код

  if P.MakeSMTPSession('194.67.23.111','test@','test@','тест') then
    showmessage('OK')
 else
  showmessage('False');
  P.Disconnect;


 

Автор: Snowy 18.4.2006, 11:51
Цитата(denks @  18.4.2006,  11:18 Найти цитируемый пост)
Отправляю на mail.ru. Сообщения не доходят. Подскажите пожалуйста в чём причина
mail.ru фильтрует тебя, как спамера. 

Автор: denks 18.4.2006, 12:36
Matematik, отправляет. На 1 из ящиков сообщения доходят каждый раз. на остальные не доходят вообще. хотя все ящики на mail.ru. вот и хочу понять в чём причина. 

Автор: Matematik 18.4.2006, 13:03
Ну раз отправляешь правильно, тогда 
Цитата(Snowy @  18.4.2006,  12:51 Найти цитируемый пост)
mail.ru фильтрует тебя, как спамера. 

 

Автор: denks 18.4.2006, 13:36
А как тогда отправлять ? 

Автор: Matematik 18.4.2006, 13:49
1. Использовать другой компонент.
2. Если с помощью этого кода, тогда надо MakeSMTPSession исправить на отправку нескильким юзверям, например

Код

unit mail;
interface    
uses    
  Windows, WinSock;    
const    
  CRLF = #13#10;    
  CSMTPCommands: array[0..20, 0..1] of String = (    
    ('211', 'System status, or system help reply'),
    ('214', 'Help message'),    
    ('220', 'Service ready'),    
    ('221', 'Service closing transmission channel'),    
    ('250', 'Requested mail action okay, completed'),    
    ('251', 'User not local'),    
    ('354', 'Start mail input'),    
    ('421', 'Service not available, closing transmission channel'),    
    ('450', 'Requested mail action not taken: mailbox unavailable'),    
    ('451', 'Requested action aborted: local error in processing'),    
    ('452', 'Requested action not taken: insufficient system storage'),    
    ('500', 'Syntax error, command unrecognized'),    
    ('501', 'Syntax error in parameters or arguments'),    
    ('502', 'Command not implemented'),    
    ('503', 'Bad sequence of commands'),    
    ('504', 'Command parameter not implemented'),    
    ('550', 'Requested action not taken: mailbox unavailable'),    
    ('551', 'User not local'),    
    ('552', 'Requested mail action aborted: exceeded storage allocation'),    
    ('553', 'Requested action not taken: mailbox name not allowed'),    
    ('554', 'Transaction failed')    
  );    
  {SMTP Error Codes}    
  ERR_NOERROR = 0;    
  ERR_SMTP_MALFORMED = 1;    
  ERR_SMTP_UNK_COMMAND = 2;    
  ERR_ONCMD_STR = 3;    
  ERR_RECV = 4;    
  ERR_SEND = 5;    
type    
  TTextSocket = class(TObject)    
  private    
    FSocket: TSocket;    
  public    
    function Connect(const Host: String; Port: Word): Boolean;    
    procedure Disconnect;    
    function ReceiveData(var Buffer: String): Boolean;    
    function SendData(var Data; Len: Integer): Boolean;    
  end;    
  TTextProtocol = class(TTextSocket);    
  TSMTPProtocol = class(TTextProtocol)    
  private    
    FLastError: Integer;    
    FLastErrorStr: String;    
    procedure MakeStringError(const Command: String);    
     
    {SEND}    
    function MakeCommand(const Value: String): String;    
    function MakeHello(const Host: String): String;    
    function MakeMailFrom(const User: String): String;    
    function MakeMailTo(const User: String): String;    
    function MakeDataStart: String;    
    function MakeData(const Data: String): String;    
    function MakeQuit: String;    
    function SendSMTPCommand(Command: String): Boolean;    
    {RECV}    
    function CheckIfValidCommand(const Value: String): Integer;    
    function RecvSMTPCommand(var Command: String): Boolean;    
  public    
    function MakeSMTPSession1(const Host, UserFrom, UserTo, Data: String): Boolean;    
    function MakeSMTPSession(const Host, UserFrom, Data: String;const UserTo:Array of String): Boolean;
    property LastError: Integer read FLastError;
    property LastErrorStr: String read FLastErrorStr;    
  end;    
var    
  WSAData: TWSAData;    
  FWSAStarted: Boolean;    
implementation    
{SMTP}    
function TSMTPProtocol.MakeCommand(const Value: String): String;    
begin    
  Result := Value + CRLF;    
end;    
function TSMTPProtocol.MakeHello(const Host: String): String;    
begin    
  Result := MakeCommand('EHLO ' + Host);    
end;    
function TSMTPProtocol.MakeMailFrom(const User: String): String;    
begin    
  Result := MakeCommand('MAIL FROM:' + User);    
end;    
function TSMTPProtocol.MakeMailTo(const User: String): String;    
begin    
  Result := MakeCommand('RCPT TO:' + User);    
end;    
function TSMTPProtocol.MakeDataStart: String;    
begin    
  Result := MakeCommand('DATA');    
end;    
function TSMTPProtocol.MakeData(const Data: String): String;    
var f:file;    
d:file;    
FileBuf : AnsiString;    
FileBuf1: AnsiString;    
p:AnsiString;    
begin    
AssignFile(F,'c:\test.txt');    
      FileMode:=0;    
      {$I-}    
      Reset(F,1);    
      IF IOResult=0 THEN BEGIN    
        SetLength(FileBuf,FileSize(F));    
        BlockRead(F,FileBuf[1],FileSize(F));    
        CloseFile(F);    
        end;    
  Result := MakeCommand('тест '  + CRLF + CRLF + Data + CRLF +'Content-Type: application/x-shockwave-flash;'#13#10+
             '    name="'+'тест'+'"'#13#10 +filebuf+crlf+'тест'#13#10+filebuf1+'.');    
end;    
function TSMTPProtocol.MakeQuit: String;    
begin    
  Result := MakeCommand('QUIT');    
end;    
function TSMTPProtocol.CheckIfValidCommand(const Value: String): Integer;    
var    
  Command: String;    
  i: Integer;    
begin    
  if Length(Value) < 4 then begin    
    Result := ERR_SMTP_MALFORMED;    
    Exit;    
  end;    
  Command := Copy(Value, 0, 3);    
  for i := Low(CSMTPCommands) to High(CSMTPCommands) do    
    if CSMTPCommands[i, 0] = Command then begin    
      Result := ERR_NOERROR;    
      Exit;    
    end;    
  Result := ERR_SMTP_UNK_COMMAND;    
  FLastErrorStr := Command;    
end;    
function TSMTPProtocol.RecvSMTPCommand(var Command: String): Boolean;    
var    
  RcvData: String;    
begin    
  if not ReceiveData(RcvData) then begin    
    FLastError := ERR_RECV;    
    Result := False;    
    Exit;    
  end;    
  FLastError := CheckIfValidCommand(RcvData);    
  Result := FLastError = ERR_NOERROR;    
  if Result then    
    Command := Copy(RcvData, 0, 3)    
end;    
function TSMTPProtocol.SendSMTPCommand(Command: String): Boolean;    
begin    
  {SendData}    
  Result := SendData(Command[1], Length(Command));    
  if not Result then    
    FLastError := ERR_SEND;    
end;    
procedure TSMTPProtocol.MakeStringError(const Command: String);    
var    
  i: Integer;    
begin    
  for i := Low(CSMTPCommands) to High(CSMTPCommands) do    
    if CSMTPCommands[i, 0] = Command then begin    
      FLastError := ERR_ONCMD_STR;    
      FLastErrorStr := CSMTPCommands[i, 1];    
    end;    
end;    
function TSMTPProtocol.MakeSMTPSession1(const Host, UserFrom, UserTo, Data: String): Boolean;
begin
  Result := MakeSMTPSession(Host, UserFrom, Data, [UserTo]);
end;

function TSMTPProtocol.MakeSMTPSession(const Host, UserFrom, Data: String;const UserTo:Array of String): Boolean;
var
  Command: String;
  j:Integer;
begin
  Result := False;
  FLastError := ERR_NOERROR;
  {Receive Server's Greeting}
  if not RecvSMTPCommand(Command) then Exit;
  if Command <> '220' then begin
     MakeStringError(Command);
     Exit;
  end;
  {HELO}
  if not SendSMTPCommand(MakeHello('localhost')) then Exit;
  if not RecvSMTPCommand(Command) then Exit;
  if Command <> '250' then begin
     MakeStringError(Command);
     Exit;
  end;
  {MAIL FROM: user@domain.com}
  if not SendSMTPCommand(MakeMailFrom(UserFrom)) then Exit;
  if not RecvSMTPCommand(Command) then Exit;
  if Command <> '250' then begin
     MakeStringError(Command);
     Exit;
  end;
  for j:=Low(UserTo) to High(UserTo) do
  begin
  {RCPT TO: user@domain.com}
    if not SendSMTPCommand(MakeMailTo(UserTo[j])) then Exit;
    if not RecvSMTPCommand(Command) then Exit;
    if Command <> '250' then begin
       MakeStringError(Command);
       Exit;
    end;
  end;
  {DATA}
  if not SendSMTPCommand(MakeDataStart) then Exit;
  if not RecvSMTPCommand(Command) then Exit;
  if Command <> '354' then begin
     MakeStringError(Command);
     Exit;
  end;
  {Message Body}
  if not SendSMTPCommand(MakeData(Data)) then Exit;
  if not RecvSMTPCommand(Command) then Exit;
  if Command <> '250' then begin
     MakeStringError(Command);
     Exit;
  end;
  {QUIT}
  if not SendSMTPCommand(MakeQuit) then Exit;
  Result := True;
end;


{ TTextSocket }
function TTextSocket.Connect(const Host: String; Port: Word): Boolean;
var
  addr: Integer;
  sockaddr: sockaddr_in;
begin
  Result := False;
  if not FWSAStarted then Exit;
  FSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if FSocket = INVALID_SOCKET then Exit;
  addr := inet_addr(PChar(Host));
  if addr = INADDR_NONE then Exit;
  sockaddr.sin_family := AF_INET;
  sockaddr.sin_port := htons(Port);
  sockaddr.sin_addr.S_addr := addr;
  Result := WinSock.connect(FSocket, sockaddr, sizeof(sockaddr)) <> SOCKET_ERROR;
end;
procedure TTextSocket.Disconnect;
begin
  if FSocket <> INVALID_SOCKET then begin
    closesocket(FSocket);
    FSocket := INVALID_SOCKET;
  end;
end;
function TTextSocket.ReceiveData(var Buffer: String): Boolean;
var
  LocBuf: array[0..1023] of Byte;
  RecvLen: Integer;
  function IsComplete: Boolean;
  begin
    Result := (Length(Buffer) > 1) and (Buffer[Length(Buffer)-1] = #13) and (Buffer[Length(Buffer)] = #10);
  end;
begin
  Buffer := '';
  Result := False;
  while True do begin
    RecvLen := recv(FSocket, LocBuf, SizeOf(LocBuf)-1, 0);
    if RecvLen = SOCKET_ERROR then
      Exit
    else if RecvLen = 0 then
      Break
    else begin
      LocBuf[RecvLen] := 0;
      Buffer := Buffer + Copy(PChar(@LocBuf), 0, RecvLen);
      if IsComplete then begin
        Result := True;
        Exit;
      end;
    end;
  end;
  Result := IsComplete;
end;
function TTextSocket.SendData(var Data; Len: Integer): Boolean;
begin
  Result := send(FSocket, Data, Len, 0) <> SOCKET_ERROR;
end;
initialization
  FWSAStarted := WSAStartup(MAKEWORD(1, 1), WSAData) = 0;
finalization
  if FWSAStarted then
    WSACleanup;
end.



Код не тестил, но должен работать.

Добавлено @ 13:50 
Отправлять одним заходом.
Код


P.MakeSMTPSession('194.67.23.111','test@mail.ru','тест',['почта1','почта2','почта3'])

 

Автор: denks 18.4.2006, 14:21
Спасибо. Всё работает кроме отправки самому себе. С этим можно что-нибудь сделать ? 

Автор: Matematik 18.4.2006, 14:36
Цитата(denks @  18.4.2006,  15:21 Найти цитируемый пост)
 кроме отправки самому себе

У меня мои сообшения доходят. 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)