![]() |
|
|
#1
|
||||
|
||||
|
Кто-нибудь пробовал отправлять почту через сокеты? Никак не могу победить это дело.
|
|
#2
|
||||
|
||||
|
было, но очень-очень давно. боюсь еще на дискетах исходники остались)
|
|
#3
|
||||
|
||||
|
А что конкретно не получается? Слышал, что SMTP сейчас всё чаще требуют какую-то замудренную авторизацию, которая может стать камнем преткновения.
|
|
#4
|
||||
|
||||
|
Нужна, как называют школяры, "скрытная" отправка. То есть, программа подключена по Com-порту к железке и при некоторых критических действиях должна отсылать пользователю уведомление. Набираю команды в Telnet-е, всё нормально, на те же команды из программы получаю ответ - Нераспознанная команда. Взял довольно распространённый в сети код и пытаюсь экспериментировать с ним.
Код:
function CreateMailMessage : Boolean;
type
TaPInAddr = array[0..10] of PInAddr;
PaPInAddr = ^TaPInAddr;
var
WSAData : TWSAData;
Host : TSockAddrIn;
Sock : TSocket;
HostE : PHostEnt;
Server : AnsiString;
function SendData(St : AnsiString) : Boolean;
var
Buf : array[0..1023] of AnsiChar;
begin
FillChar(Buf, SizeOf(Buf), 0);
MoveMemory(@Buf[0], @St[1], Length(St));
Result := send(Sock, Buf, Length(St) + 1, 0) > SOCKET_ERROR + 1;
end;
function RecvData(accept : AnsiString) : BOOL;
var
Buf : array[0..1023] of AnsiChar;
begin
res := recv(Sock, Buf, SizeOf(Buf), 0);
Result := (Res = SOCKET_ERROR) or (Copy(Buf, 0, 3) = accept);
end;
begin
Result := False;
WSAStartUp(257, WSAData);
try
Sock := socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if Sock = INVALID_SOCKET then
Exit;
try
Server := Copy(Settings.Mail, Pos('@', Settings.Mail) + 1, Length(Settings.Mail));
HostE := GetHostByName(PAnsiChar('smtp.' + Server));
if HostE = NIL then
Exit;
FillChar(Host, SizeOf(TSockAddrIn), 0);
Host.sin_family := AF_INET;
Host.sin_port := htons(25);
Host.sin_addr.S_addr := inet_addr(inet_ntoa(PInAddr(HostE.h_addr_list^)^));
if connect(Sock, Host, SizeOf(Host)) > 0 then
Exit;
if not RecvData('220') then
Exit;
// EHLO
SendData('EHLO ' + Server + #13#10);
if not RecvData('250') then
Exit;
SendData('STARTTLS'#13#10);
if not RecvData('250') then // Тут уже сбой
Exit;
SendData('AUTH LOGIN'#13#10);
if not RecvData('250') then
Exit;
// MAIL FROM:
SendData('MAIL FROM:' + Settings.Mail + #13#10);
if not RecvData('250') then
Exit;
// RCPT TO:
SendData('RCPT TO:' + Settings.Mail + #13#10);
if not RecvData('250') then
Exit;
// DATA
SendData('DATA' + #13#10);
if not RecvData('354') then
Exit;
SendData('Subject: ' + 'MAP monitoring - Error' + #13#10#13#10 + 'Test' + #13#10 + '.');
if not RecvData('250') then
Exit;
SendData('QUIT' + #13#10);
Result := True;
finally
closesocket(sock);
end;
finally
WSACleanup;
end; |
|
#5
|
||||
|
||||
|
А что возвращается-то?
Добавлено позже: функция SendData кривая какая-то, будто еще под Turbo Pascal писана. Я бы написал так: Код:
function SendData(St : AnsiString) : Boolean; begin Result := send(Sock, St[1], Length(St) + 1, 0) > SOCKET_ERROR + 1; end; Последний раз редактировалось Freeman, 27.03.2014 в 01:37. |
|
#6
|
||||
|
||||
|
Хоть извращайся, хоть нет, а заказчику нужна отправка на почту.
Да 0 требуется, из-за этого и буфер. |
|
#7
|
||||
|
||||
|
Цитата:
Добавлено позже: кстати, у Borland: Код:
function TBaseSocket.SendBuf(var Buf; BufSize: Integer; Flags: Integer): Integer;
begin
DoSend(pchar(@Buf), BufSize);
Result := ErrorCheck(Send(FSocket, Buf, BufSize, Flags));
if Result <> SOCKET_ERROR then
inc(FBytesSent, Result);
end;
function TBaseSocket.Sendln(s: string; const eol: string): Integer;
begin
s := s + eol;
Result := SendBuf(pchar(s)^, length(s), 0);
end;![]() Последний раз редактировалось Freeman, 27.03.2014 в 03:13. |
|
#8
|
||||
|
||||
|
По фигу что там у Borland-а. Любая команда после приветствия считается нераспознанной.
0 не отправляется, а служит признаком завершения строки - так принято у С-ников. |
|
#9
|
||||
|
||||
|
Цитата:
Код:
'EHLO'#13#10 #0'STARTTLS'#13#10 |
|
#10
|
||||
|
||||
|
Получается всё правильно, в отладчике проверял.
|
|
#11
|
||||
|
||||
|
В ответ на STARTTLS mail.yandex.ru мне возвращает "220 Go ahead", а не 250, как ожидается в коде.
|
|
#12
|
||||
|
||||
|
Я проверяю для Гугла.
Хм, Яндекс вернул - Ошибка синтаксиса. Последний раз редактировалось angvelem, 27.03.2014 в 04:57. |
|
#13
|
||||
|
||||
|
Без разницы. GMail мне возвращает '220 2.0.0 Ready to start TLS'. Это же по RFC, не они их сами выдумали.
|
|
#14
|
||||
|
||||
|
Через Telnet так и возвращает, в коде не хочет.
Насчёт выдумки, знакомый решил потестировать на своём сайте, так у него все команды через одно место, почти ни одна не совпала с RFC. |
|
#15
|
||||
|
||||
|
Цитата:
Код:
function SendData(St : AnsiString) : Boolean; begin Result := send(Sock, St[1], Length(St), 0) > SOCKET_ERROR + 1; end; ![]() |