сабж. требуется отправить письмо на ящик reciever@yandex.ru сожержащее в body кое-какие данные. "отпраивтель" - без разницы, главное - содержание письма и его доставка по назначению. smtp ya.ru: 213.180.204.3 , port: 25. нарыл код, который вроде реализует через сокеты (не работал с ними раньше) (нарыл здась: /showthread.php?p=671692) после небольшой редакции компилица, трассируеца... сниффаеца. Code: TCP 192.168.0.100 2652 205.188.12.134 5190 132 байт и, соответственно, нифига не работает так, как должен =\ код: Code: 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 (или как альтернатива - аттачменте) те или иные "данные" (текстовый файл)
Любое письмо так посланное будет скорее всего в спаме. К таму же тебе нужно не на абы какие адреса слать письма, а именно на MX шлюзы(потому что тока они принимают письма без авторизации и с левых адресов) Когдато давно писал примитивную тестовую версию для этих целей Code: 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 - его можно где угодно найти в инете. или если нужно то вот. Code: //****************************************************************************** // 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.
Ну яндекс самый лоальный к такого роду письмам. А вот на AOL, HOTMAIL и MAIL.RU ты врядли вообще сможешь отправить сообщение.
*отправил себе примерно 10 сообщений, поленился удалить их из спама - сервер блокнул дальнейший прием сообщений с того IP. Разумно. *как добавлять аттачменты(этим методом) - не фкурил, но, почитав фак по командам SMTP пришел к выводу, что скорее всего никак. (http://book.itep.ru/4/44/smtp4414.htm - неплохой фак) *данные, содержищие специальные и не читаемые символы можно удобно пересылать, предварительно проеобразовав их в hex формат.
4 функции для преобразования текста в hex и обратно: построчно и по-символьно. Если вдруг вам когда-либо нужно будет надо переслать себе по почте(из консоли) файл, содержащий служебные или спец. символы... Code: {преобразовать строку в 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; очень удобно. И не надо никаких аттачментов.
хорошая ссылка, пусть тоже будет тут. зы. 100% того, мне было "нужно" я уже реализовал с помощью кода slesh. Причем, как и хотел, с использованием одного лишь winsock. Сюда же докидываю инфу, которая может в дальнейшем пригодиться тем, кому так же как и мне нужно будет наладить пересылку сообщений (и файлов) по SMTP из консоли средствами одного лишь win-api
обратил внимание, что на этот код просто _нереально_ "обозлилась" целая куча а-вирей. =\ Не кошерно. Использовать 'as is' нельзя. Проблема, как ни странно, решается редактированием всего-лишь одной строки кода.