Форум АНТИЧАТ

Форум АНТИЧАТ (https://forum.antichat.xyz/index.php)
-   С/С++, C#, Delphi, .NET, Asm (https://forum.antichat.xyz/forumdisplay.php?f=24)
-   -   письмо по SMTP из консоли. Delphi. (https://forum.antichat.xyz/showthread.php?t=132897)

ErrorNeo 03.08.2009 21:44

письмо по SMTP из консоли. Delphi.
 
сабж.

требуется отправить письмо на ящик reciever@yandex.ru
сожержащее в body кое-какие данные.
"отпраивтель" - без разницы, главное - содержание письма и его доставка по назначению.
smtp ya.ru: 213.180.204.3 , port: 25.

нарыл код, который вроде реализует через сокеты (не работал с ними раньше)
(нарыл здась: http://forum.antichat.ru/showthread.php?p=671692)

после небольшой редакции компилица, трассируеца... сниффаеца.
Код:

TCP       
192.168.0.100        2652
205.188.12.134        5190                               
132 байт

и, соответственно, нифига не работает так, как должен =\

код:

Код:

program Project1;

uses
  SysUtils,
  Winsock,
  Windows;

{
smtp - ip адрес smtp сервера
port - порт smtp сервера, по умолчанию 25
from - адрес отправителя
dest - адрес получателя
subject - тема письма
body - текст писма
Возвращает True если письмо было успешно отправленно...
}
function mail(smtp: string; port: integer; from, dest, subject, body: string): bool;
const
  cl = #13#10;
var
WSAData: TWSAData;
  Host: TSockAddrIn;
  Sock: TSocket;
  res: Integer;
  buff: array[1..255] of Char;

  { отправляем данные через сокет }
  procedure senddata(str: string);
  var
    i: integer;
  begin
    for i := 1 to Length(str) do
      if send(Sock, str[i], 1, 0) = SOCKET_ERROR then
        exit;
  end;
  { получаем ответ от команды }
  function recvdata(accept: string): bool;
  var
    buff: array[1..255] of Char;
  begin
    res := recv(Sock, buff, SizeOf(buff), 0);
    Result := ((Res = SOCKET_ERROR) or (Copy(buff, 1, 3) = accept));
  end;
begin
  try
    result := false;
    { инициализация сокета }
    WSAStartUp(257, WSAData);
    Sock := socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    if Sock = INVALID_SOCKET then
      Exit;
    { устанавливаем хост и порт сервера }
    res := inet_addr(PChar(smtp));
    if res <= 0 then
      exit;
    Host.sin_family := AF_INET;
    Host.sin_port := htons(port);
    Host.sin_addr.S_addr := res;
    { подключаемся к серверу }
    if connect(Sock, Host, SizeOf(Host)) > 0 then
      Exit;
    { приветствие сервера }
    if not recvdata('220') then
      Exit;
    { EHLO }
    senddata('EHLO' + cl);
    if not recvdata('250') then
      Exit;
    { MAIL FROM: }
    senddata('MAIL FROM:' + from + cl);
    if not recvdata('250') then
      Exit;
    { RCPT TO: }
    senddata('RCPT TO:' + dest + cl);
    if not recvdata('250') then
      Exit;
    { DATA }
    senddata('DATA' + cl);
    if not recvdata('354') then
      Exit;
    { отправляем текст сообщения }
    senddata('Subject:' + subject + cl + cl + body + cl + '.');
    if not recvdata('250') then
      Exit;
    { отключаемся от сервера }
    senddata('QUIT' + cl);
    result := true;
  finally
    { убиваем сокет }
    closesocket(sock);
    WSACleanup;
  end;
end;

//----------------------------------------------

begin

  mail('213.180.204.3',25,'reciever@yandex.ru' ,'admin@company.mail', 'subj', 'body text');

end.

сабж мне как бэ нужен, так что разбирусь и сам..
но за любую помощь буду признателен.
Как по данному коду, так и по любому другому, _рабочему_ методу отправки e-mail на заранее заданный адрес на заранее заданном почтовике, содержащему в body (или как альтернатива - аттачменте) те или иные "данные" (текстовый файл)

slesh 03.08.2009 22:10

Любое письмо так посланное будет скорее всего в спаме.
К таму же тебе нужно не на абы какие адреса слать письма,
а именно на MX шлюзы(потому что тока они принимают письма без авторизации и с левых адресов)

Когдато давно писал примитивную тестовую версию для этих целей

Код:

program sm;

{$APPTYPE CONSOLE}

uses
  Windows,WinDNS,Winsock;

function MXResolve(Domain: PChar): string;
var
pQueryResultsSet: PDNS_RECORDA;
Name: PChar;
begin
pQueryResultsSet := nil;
if DnsQuery_A(Domain, DNS_TYPE_MX, DNS_QUERY_STANDARD, nil, @pQueryResultsSet, nil) = 0 then
 begin
  Result:=pQueryResultsSet^.Data.MX.pNameExchange;
  GlobalFree(dword(pQueryResultsSet));
 end;
end;

function GetIPAddress(name: string): string;
var
  p: PHostEnt;
begin
p:=GetHostByName(PChar(name));
if p=nil then result:=name else
result:=inet_ntoa(PInAddr(p.h_addr_list^)^);
end;


var
buf:array[0..1023] of char;
s:string;
f:textfile;
c:char;
mail_from,mail_to,mail_file:string;
MX_SERVER:string;
WSData:TWSAData;
so:thandle;
ca:sockaddr_in;
begin
writeln('SendMail (C) SLESH (ICQ: 266-334-734)');
writeln('Usage: sm.exe MAIL_FROM MAIL_TO MAIL_FILE');


mail_from:=paramstr(1);
mail_to:=paramstr(2);
mail_file:=paramstr(3);

if (mail_from='') or (mail_to='') or (mail_file='') then exit;

MX_SERVER:=MAIL_TO;
delete(MX_SERVER,1,pos('@',MX_SERVER));
write('[*] WSAStartup...');
if WSAStartup($101, WSData)=-1 then begin write('ERROR');exit;end;
writeln('OK');

write('[*] RESOLVE MX SERVER...');
MX_SERVER:=MXResolve(Pansichar(MX_SERVER));
if MX_SERVER='' then
 begin
  write('ERROR');
  exit;
 end;
writeln('OK');
write('[*] RESOLVE IP MX SERVER...');
MX_SERVER:=GetIPAddress(MX_SERVER);
if MX_SERVER='' then
 begin
  write('ERROR');
  exit;
 end;
writeln('OK');
write('[*] Create Socket...');
so:=socket(AF_INET, SOCK_STREAM, 0);
if so=-1 then begin
writeln('ERROR');
exit;
end;
writeln('OK');

ca.sin_family:=AF_INET;
ca.sin_port:=htons(25);
ca.sin_addr.s_addr:=inet_addr(Pansichar(MX_SERVER));
write('[*] Connect to server...');
if connect(so,ca,sizeof(ca))=-1 then begin
closesocket(so);
writeln('ERROR');
exit;
end;
writeln('OK');
recv(so,buf,sizeof(buf),0);
s:='EHLO server'+#13#10;
send(so,s[1],length(s),0);
recv(so,buf,sizeof(buf),0);
if copy(buf,1,3)<>'250' then
 begin
  writeln('[-] HELO ERROR');
  writeln(buf);
  exit;
 end;

s:='MAIL FROM:<'+MAIL_FROM+'>'+#13#10;
send(so,s[1],length(s),0);
recv(so,buf,sizeof(buf),0);
if copy(buf,1,3)<>'250' then
 begin
  writeln('[-] MAIL FROM ERROR');
  writeln(buf);
  exit;
 end;

s:='RCPT TO:<'+MAIL_TO+'>'+#13#10;
send(so,s[1],length(s),0);
recv(so,buf,sizeof(buf),0);
if copy(buf,1,3)<>'250' then
 begin
  writeln('[-] RCPT TO ERROR');
  writeln(buf);
  exit;
 end;

s:='DATA'+#13#10;
send(so,s[1],length(s),0);
recv(so,buf,sizeof(buf),0);
if copy(buf,1,3)<>'354' then
 begin
  writeln('[-] DATA ERROR');
  writeln(buf);
  exit;
 end;

assignfile(f,mail_file);
reset(f);
while not eof(f) do begin
readln(f,s);
s:=s+#13#10;
send(so,s[1],length(s),0);
end;
closefile(f);
s:=#13#10+'.'+#13#10;
send(so,s[1],length(s),0);
recv(so,buf,sizeof(buf),0);
if copy(buf,1,3)<>'250' then
 begin
  writeln('[-] SEND ERROR');
  writeln(buf);
  exit;
 end;
s:='QUIT'+#13#10;
send(so,s[1],length(s),0);
recv(so,buf,sizeof(buf),0);
if copy(buf,1,3)<>'221' then
 begin
  writeln('[-] QUIT ERROR');
  writeln(buf);
  exit;
 end;
closehandle(so);
writeln('[+] SEND OK');
end.

Для работу нужен модуль WinDNS - его можно где угодно найти в инете.
или если нужно то вот.
Код:

//******************************************************************************
// Nom          : WinDns.pas
// Utilisation  : Fonction et Type pour l'acces a DnsApi.dll
// Auteur        : uncle_khemi@hotmail.com
// Date          : 27 Aout 2003
//
// Modifications :
// Date          :
//******************************************************************************

unit WinDNS;

interface
uses
  Windows;

const
  //  Options for DnsQuery
  DNS_QUERY_STANDARD = 0;
  DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE = 1;
  DNS_QUERY_USE_TCP_ONLY = 2;
  DNS_QUERY_NO_RECURSION = 4;
  DNS_QUERY_BYPASS_CACHE = 8;

  //autres
  DNS_ATMA_MAX_ADDR_LENGTH = 20;
  DNS_ATMA_AESA_ADDR_LENGTH = 20;

  DNS_TYPE_A = 1;
  DNS_TYPE_CNAME = 5;
  DNS_TYPE_PTR = 12;
  DNS_TYPE_MX = 15;

  DNS_UPDATE_SECURITY_USE_DEFAULT = 0;

type
  IP6_ADDRESS = array[0..3] of dword;
  IP4_ADDRESS = DWORD;
  DNS_A_DATA = IP4_ADDRESS;
  DNS_PTR_DATA = PChar;
  DNS_PTR_DATAA = DNS_PTR_DATA;
  DNS_PTR_DATAW = DNS_PTR_DATA;
  DNS_AAAA_DATA = IP6_ADDRESS;
  DNS_STATUS = LongInt;
  PIP4_ARRAY = ^IP4_ARRAY;

  //validation d'un nom DNS
  DNS_NAME_FORMAT = (DnsNameDomain,
    DnsNameDomainLabel,
    DnsNameHostnameFull,
    DnsNameHostnameLabel,
    DnsNameWildcard,
    DnsNameSrvRecord);

  //definie le type de liberation pour avec DnsFreeRecordList
  DNS_FREE_TYPE = (
    DnsFreeFlat,
    DnsFreeRecordList,
    DnsFreeParsedMessageFields
    );

  //tableau d'adresse IP
  IP4_ARRAY = record
    AddrCount: DWORD;
    AddrArray: array[0..10] of IP4_ADDRESS; //[0..10]
  end;

  DNS_SRV_DATAA = record
    pNameTarget: PChar;
    wPriority: Word;
    wWeighty: Word;
    wPorty: Word;
    Pady: Word;                        // keep ptrs DWORD aligned
  end;

  DNS_TSIG_DATAA = record
    pNameAlgorithm: PChar;
    pAlgorithmPacket: ^Byte;
    pSignature: ^Byte;
    pOtherData: ^Byte;
    i64CreateTime: longlong;
    wFudgeTime: Word;
    wOriginalXid: Word;
    wError: Word;
    wSigLength: Word;
    wOtherLength: Word;
    cAlgNameLength: UCHAR;
    bPacketPointers: Boolean;
  end;

  DNS_NXT_DATAA = record
    pNameNext: PChar;
    wNumTypes: Word;
    wTypes: array[0..1] of Word;
  end;

  DNS_WINSR_DATA = record
    dwMappingFlag: DWORD;
    dwLookupTimeout: DWORD;
    dwCacheTimeout: DWORD;
    pNameResultDomain: PWideChar;
  end;

  DNS_WINSR_DATAA = record
    dwMappingFlag: DWORD;
    dwLookupTimeout: DWORD;
    dwCacheTimeout: DWORD;
    pNameResultDomain: PChar;
  end;

  DNS_RECORD_FLAGS = record
    Section: DWORD;                    //DWORD  Section    : 2;
    Delete: DWORD;                      //DWORD  Delete      : 1;
    CharSet: DWORD;                    //DWORD  CharSet    : 2;
    Unused: DWORD;                      //DWORD  Unused      : 3;
    Reserved: DWORD;                    //DWORD  Reserved    : 24;
  end;

  DNS_TXT_DATAA = record
    dwStringCount: DWORD;
    pStringArray: array[0..10] of PChar;
  end;

  DNS_NULL_DATA = record
    dwByteCount: DWORD;
    Data: array[0..10] of Byte;
  end;

  DNS_KEY_DATA = record
    wFlags: Word;
    chProtocol: Byte;
    chAlgorithm: Byte;
    Key: array[0..0] of Byte;
  end;

  DNS_SIG_DATAA = record
    pNameSigner: PChar;
    wTypeCovered: Word;
    chAlgorithm: Byte;
    chLabelCount: Byte;
    dwOriginalTtl: DWORD;
    dwExpiration: DWORD;
    dwTimeSigned: DWORD;
    wKeyTag: Word;
    Pad: Word;                          // keep Byte field aligned
    Signature: array[0..0] of Byte;
  end;

  DNS_ATMA_DATA = record
    AddressType: Byte;
    Address: array[0..(DNS_ATMA_MAX_ADDR_LENGTH - 1)] of Byte;
  end;

  DNS_WKS_DATA = record
    IpAddress: IP4_ADDRESS;
    chProtocol: UCHAR;
    BitMask: array[0..0] of Byte;      // BitMask[1];
  end;

  DNS_MX_DATAA = record
    pNameExchange: PChar;
    wPreference: Word;
    Pad: Word;
  end;

  DNS_MINFO_DATAA = record
    pNameMailbox: PChar;
    pNameErrorsMailbox: PChar;
  end;

  DNS_WINS_DATA = record
    dwMappingFlag: DWORD;
    dwLookupTimeout: DWORD;
    dwCacheTimeout: DWORD;
    cWinsServerCount: DWORD;
    WinsServers: array[0..0] of IP4_ADDRESS;
  end;

  DNS_TKEY_DATAA = record
    pNameAlgorithm: PChar;
    pAlgorithmPacket: ^Byte;
    pKey: ^Byte;
    pOtherData: ^Byte;
    dwCreateTime: DWORD;
    dwExpireTime: DWORD;
    wMode: Word;
    wError: Word;
    wKeyLength: Word;
    wOtherLength: Word;
    cAlgNameLength: UCHAR;
    bPacketPointers: Boolean;
  end;

  DNS_SOA_DATAA = record
    pNamePrimaryServer: PChar;
    pNameAdministrator: PChar;
    dwSerialNo: DWORD;
    dwRefresh: DWORD;
    dwRetry: DWORD;
    dwExpire: DWORD;
    dwDefaultTtl: DWORD;
  end;

  //probleme non resolu lorsqu'on utilise les flags de type S
  TFlags = record
    case Integer of
      1: (DW: DWORD);                  // flags as DWORD
      2: (S: ^DNS_RECORD_FLAGS);        // flags as structure  ???
  end;

  TDataA = record
    case Integer of
      1: (A: DNS_A_DATA);              //    A;
      2: (SOA: DNS_SOA_DATAA);          //  SOA, Soa;
      3: (PTR: DNS_PTR_DATAA);          //PTR, Ptr, NS, Ns, CNAME, Cname, MB, Mb, MD, Md, MF, Mf, MG, Mg, MR, Mr;
      4: (MINFO: DNS_MINFO_DATAA);      //MINFO, Minfo,    RP, Rp;
      5: (MX: DNS_MX_DATAA);            //MX, Mx,        AFSDB, Afsdb,            RT, Rt;
      6: (HINFO: DNS_TXT_DATAA);        //HINFO, Hinfo,        ISDN, Isdn,        TXT, Txt,          X25;
      7: (Null: DNS_NULL_DATA);        //Null;
      8: (WKS: DNS_WKS_DATA);          //WKS, Wks;
      9: (AAAA: DNS_AAAA_DATA);        //AAAA;
      10: (KEY: DNS_KEY_DATA);          //KEY, Key;
      11: (SIG: DNS_SIG_DATAA);        //SIG, Sig;
      12: (ATMA: DNS_ATMA_DATA);        //ATMA, Atma;
      13: (NXT: DNS_NXT_DATAA);        //NXT, Nxt;
      14: (SRV: DNS_SRV_DATAA);        //SRV, Srv;
      15: (TKEY: DNS_TKEY_DATAA);      //TKEY, Tkey;
      16: (TSIG: DNS_TSIG_DATAA);      //TSIG, Tsig;
      17: (DWINS: DNS_WINS_DATA);      //WINS, Wins;
      18: (WINSR: DNS_WINSR_DATA);      //WINSR, WinsR, NBSTAT, Nbstat;
  end;



  PDNS_RECORDA = ^DNS_RECORDA;
  DNS_RECORDA = record
    pnext: PDNS_RECORDA;                //  struct _DnsRecordW *
    pName: PChar;                      //PSTR
    wType: Word;                        //WORD                                              //WORD                    wType;
    wDataLength: Word;                  //WORD
    flags: TFlags;                      //
    dwTtl: DWORD;                      //DWORD;
    dwReserved: DWORD;                  //DWORD;
    Data: TDataA;
  end;



  //------------------------------------------------------------------------------
  //Fonctions
  //------------------------------------------------------------------------------


  //------------------------------------------------------------------------------
  //voir un enregistrement
function DnsQuery_A(
  pszName: PChar;
  wType: Word;
  Options: DWORD;
  aipServers: PIP4_ARRAY;
  ppQueryResults: Pointer;
  pReserved: Pointer
  ): DNS_STATUS; stdcall; external 'dnsapi.dll';
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//ajouter, modifier et supprimer un enregistrement
function DnsModifyRecordsInSet_A(
  pAddRecords: PDNS_RECORDA;
  pDeleteRecords: PDNS_RECORDA;
  Options: DWORD;
  hContext: Hwnd;
  pServerList: PIP4_ARRAY;
  pReserved: Pointer
  ): DNS_STATUS; stdcall; external 'dnsapi.dll';
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//verifie si un nom DNS est correct
function DnsValidateName_A(
  pszName: PChar;
  Format: DNS_NAME_FORMAT
  ): DNS_STATUS; stdcall; external 'dnsapi.dll';
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//supprime la memoire aloue pour la reponse par un DNS_QUERY
procedure DnsRecordListFree(
  pRecordList: PDNS_RECORDA;
  FreeType: DNS_FREE_TYPE
  ); stdcall; external 'dnsapi.dll';
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//supprime la memoire aloue pour la reponse par un DNS_QUERY
//procedure DnsFreeRecordListDeep(
//  pRecordList: PDNS_RECORDA;
//  FreeType: DNS_FREE_TYPE
//  ); stdcall; external 'dnsapi.dll';
//------------------------------------------------------------------------------



implementation

end.


slesh 03.08.2009 22:13

но знай - если у почтовика стоит SPF фильтр, то забудь про такой метод отправки.

ErrorNeo 03.08.2009 22:33

Цитата:

Дата: <date here, cut out>
От кого: sadrick@yandex.ru Это не спам… В адресную книгу… В белый список…
Кому: Noaddress
Тема: (Без темы) РаспечататьВ виде HTMLСвойства письма
koi8 | win | dos | utf-8 | mac

<message here, cut out>
+15, slesh

it works!

slesh 03.08.2009 22:49

Ну яндекс самый лоальный к такого роду письмам.
А вот на AOL, HOTMAIL и MAIL.RU ты врядли вообще сможешь отправить сообщение.

ErrorNeo 04.08.2009 15:32

*отправил себе примерно 10 сообщений, поленился удалить их из спама - сервер блокнул дальнейший прием сообщений с того IP. Разумно.

*как добавлять аттачменты(этим методом) - не фкурил, но, почитав фак по командам SMTP пришел к выводу, что скорее всего никак.
(http://book.itep.ru/4/44/smtp4414.htm - неплохой фак)

*данные, содержищие специальные и не читаемые символы можно удобно пересылать, предварительно проеобразовав их в hex формат.

ErrorNeo 04.08.2009 22:42

4 функции для преобразования текста в hex и обратно:
построчно и по-символьно.
Если вдруг вам когда-либо нужно будет надо переслать себе по почте(из консоли) файл, содержащий служебные или спец. символы...
Код:

{преобразовать строку в 16-ричный формат}
function StringToHex(S: String): String;
var I: Integer;
begin
  Result:= '';
  for I := 1 to length (S) do
    Result:= Result+IntToHex(ord(S[i]),2);
end;

{преобразовать символ в 16-ричный формат}
function ChrToHex(S: Char): String;
begin
  Result:= IntToHex(ord(S),2);
end;

{преобразовать строку в 16-ричном формате обратно в текст}
function HexToString(H: String): String;
var I: Integer;
begin
  Result:= '';
  for I := 1 to length (H) div 2 do
    Result:= Result+Char(StrToInt('$'+Copy(H,(I-1)*2+1,2)));
end;

{преобразовать "символ" в 16-ричном формате в обычный символ}
function HexToChr(H: String): Char;
begin
    Result:= Char(StrToInt('$'+Copy(H,1,2)));
end;

очень удобно. И не надо никаких аттачментов.

aqqa 04.08.2009 22:57

Чувак взгляни на это.....
http://www.glob.com.au/sendmail/sendmail.zip
Работает 100% !!!!

ErrorNeo 04.08.2009 23:24

Цитата:

Сообщение от aqqa
Чувак взгляни на это.....
http://www.glob.com.au/sendmail/sendmail.zip
Работает 100% !!!!

хорошая ссылка, пусть тоже будет тут.

зы. 100% того, мне было "нужно" я уже реализовал с помощью кода slesh. Причем, как и хотел, с использованием одного лишь winsock.

Сюда же докидываю инфу, которая может в дальнейшем пригодиться тем, кому так же как и мне нужно будет наладить пересылку сообщений (и файлов) по SMTP из консоли средствами одного лишь win-api

ErrorNeo 05.08.2009 21:10

обратил внимание, что на этот код просто _нереально_ "обозлилась" целая куча а-вирей. =\
Не кошерно.
Использовать 'as is' нельзя.
Проблема, как ни странно, решается редактированием всего-лишь одной строки кода.


Время: 14:38