Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2002.03.18;
Скачать: [xml.tar.bz2];

Вниз

E-Mail & Winsock.   Найти похожие ветки 

 
BWG   (2002-01-14 19:00) [0]

Мастера!
Понимаю, что тема избита, но так никто толком не ответил на вопрос: как написать процедуру отправки E-Mail, используя один только Winsock API. Помогите чем можите!


 
BWG   (2002-01-15 04:53) [1]

Неужели никто не знает?
Или просто лень ответить?


 
paul_shmakov   (2002-01-15 11:07) [2]

вот, только что набросал. пример показывает посылку самого простого письма. остальные поля в заголовке (типа Subject) и диалог с smtp сервером см. в rfc.
да и коды, которые сервер возвращает - это я так, на примере сейчас посмотрел - точно не помню. так что за дополнительной информацией RFC 0821.

program mail;

uses Windows, SysUtils, Winsock;

function SendMail(const From: string; const Receiver: string; const Text: string;
const SmtpHost: string; SmtpPort: Word = 25): Boolean;
var
S: TSocket;
WSData: TWSAData;

function ConnectToSmtp: Boolean;
var
Sin: SockAddr_in;
IP: DWord;
He: PHostent;
begin
Result := false;

IP := inet_addr(PChar(SmtpHost));

if INADDR_NONE = IP then
begin
He := gethostbyname(PChar(SmtpHost));
if not Assigned(He) then
Exit;
IP := PDWord(PDWord(He^.h_addr_list)^)^;
end;

S := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if INVALID_SOCKET <> S then
begin
FillChar(Sin, SizeOf(Sin), 0);
Sin.sin_family := AF_INET;
Sin.sin_port := htons(SmtpPort);
Sin.sin_addr.s_addr := IP;

Result := SOCKET_ERROR <> connect(S, Sin, SizeOf(Sin));

if not Result then
closesocket(S);
end;
end;

function SendCommand(Text: string): Boolean;
var
Buffer: PChar;
Size: Integer;
begin
Text := Text + #10;
Size := Length(Text);
GetMem(Buffer, Size + 1);
try
StrCopy(Buffer, PChar(Text));
Result := send(S, Buffer^, Size, 0) <> SOCKET_ERROR;
finally
FreeMem(Buffer);
end;
end;

function ReceiveResponse: Integer;
var
Response: string;
C: Char;
begin
Result := 0;

Response := "";
repeat
if SOCKET_ERROR = recv(S, C, SizeOf(C), 0) then
Exit;

Response := Response + C;
until C = #10;

if Pos(" ", Response) > 0 then
Result := StrToIntDef(Copy(Response, 1, Pos(" ", Response) - 1), 0)
else
Result := StrToIntDef(Response, 0);
end;

begin
Result := false;
WSAStartup($0101, WSData);
try
if ConnectToSmtp then
try
ReceiveResponse;
Result :=
SendCommand("helo delphimail") and (250 = ReceiveResponse) and
SendCommand("mail from: " + From) and (250 = ReceiveResponse) and
SendCommand("rcpt to: " + Receiver) and (250 = ReceiveResponse) and
SendCommand("data") and (354 = ReceiveResponse) and
SendCommand(Text + #10"."#10) and (250 = ReceiveResponse) and
SendCommand("quit") and (250 = ReceiveResponse);
finally
closesocket(S);
end;
finally
WSACleanup;
end;
end;

begin
SendMail("<billy@microsoft.com>", "<paul_shmakov@mail.ru>", "Hello from Billy!", "smtp.mail.ru");
end.


 
BWG   (2002-01-16 17:20) [3]

Не работает этот код. Уже застрелился понимать почему. Исправил в function SendCommand(Text: string): Boolean; строку Text := Text + #10; на Text := Text + №13#10; , строку SendMail("<billy@microsoft.com>", "<paul_shmakov@mail.ru>", "Hello from Billy!", "smtp.mail.ru"); на строку SendMail("<one@prog.ru>", "<bwgblackraven@narod.ru>", "Date: "+ DateTimeToStr(now)+#13#10+"From: one@prog.ru"+#13#10+ "To: <bwgblackraven@narod.ru>"+#13#10+"Subject: Mail"+ #13#10#13#10+"The test", "smtp.narod.ru") . Все равно не работает!

Помогите понять: ПОЧЕМУ?


 
Polevi   (2002-01-17 08:43) [4]

Коды возврата проверял ?


 
BWG   (2002-01-17 13:35) [5]

Нет вроде. Надо бы... Пошел проверять...


 
Polevi   (2002-01-17 13:43) [6]

У меня работает без всяких исправлений (кроме аргументов ф-ии)


 
paul_shmakov   (2002-01-17 13:45) [7]

может не работать по той причине, что smtp.narod.ru не позволяет вход без авторизации. попробуй telnet-ом туда подсоединиться. диалог у вас с ним примерно такой должен получиться:

220 ESMTP MAIL.RU Thu, 17 Jan 2002 13:31:42 +0300
helo delphimail
250 mx10.port.ru Hello delphimail [10.0.0.1]
mail from: <billy@microsoft.com>
250 <billy@microsoft.com> is syntactically correct
rcpt to: <paul_shmakov@mail.ru>
250 <paul_shmakov@mail.ru> verified
data
354 Enter message, ending with "." on a line by itself
hello from billy!!!
.
250 OK id=16R9qY-0007Ut-00
quit
221 mx10.port.ru closing connection

если это пройдет, то значит и программа должна работать. приведенная выше функция - это реализация этого диалога на сокетах.
правда, скорее всего потребуется авторизация :(

кстати, то, что Вы исправили #10 на #13#10 - это правильно (сейчас rfc посмотрел).

SMTP RFC 0821
http://www.ietf.org/rfc/rfc0821.txt?number=0821


 
paul_shmakov   (2002-01-17 13:57) [8]

ну и на любителей более новая версия протокола:
smtp rfc 2821
http://www.ietf.org/rfc/rfc2821.txt?number=2821


 
BWG   (2002-01-17 14:24) [9]

Протестировал так:
program TestMail;
{$APPTYPE CONSOLE}
uses
SysUtils, Winsock, Windows;

function SendMail(const From: string; const Receiver: string; const Text: string;
const SmtpHost: string; SmtpPort: Word = 25): Boolean;
var
S: TSocket;
WSData: TWSAData;

function ConnectToSmtp: Boolean;
var
Sin: SockAddr_in;
IP: DWord;
He: PHostent;
begin
Result := false;

IP := inet_addr(PChar(SmtpHost));

if INADDR_NONE = IP then
begin
He := gethostbyname(PChar(SmtpHost));
if not Assigned(He) then
Exit;
IP := PDWord(PDWord(He^.h_addr_list)^)^;
writeln("IP is ",IP);
end;

S := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if INVALID_SOCKET <> S then
begin
FillChar(Sin, SizeOf(Sin), 0);
Sin.sin_family := AF_INET;
Sin.sin_port := htons(SmtpPort);
Sin.sin_addr.s_addr := IP;

Result := SOCKET_ERROR <> connect(S, Sin, SizeOf(Sin));
if Result then writeln("Connected ok");

if not Result then
closesocket(S);
end;
end;

function SendCommand(Text: string): Boolean;
var
Buffer: PChar;
Size: Integer;
begin
Text := Text + #13#10;
Size := Length(Text);
GetMem(Buffer, Size + 1);
try
StrCopy(Buffer, PChar(Text));
Result := send(S, Buffer^, Size, 0) <> SOCKET_ERROR;
writeln("command > ",text," > result > ",result);
finally
FreeMem(Buffer);
end;
end;

function ReceiveResponse: Integer;
var
Response: string;
C: Char;
begin
Result := 0;

Response := "";
repeat
if SOCKET_ERROR = recv(S, C, SizeOf(C), 0) then
begin
writeln("Socket error!");
Exit;
end;

Response := Response + C;
until C = #10;

if Pos(" ", Response) > 0 then
Result := StrToIntDef(Copy(Response, 1, Pos(" ", Response) - 1), 0)
else
Result := StrToIntDef(Response, 0);
writeln("Resp. result > ",result);
end;

begin
Result := false;
WSAStartup($0101, WSData);
try
if ConnectToSmtp then
try
ReceiveResponse;
//Result :=
SendCommand(#32+"helo msiers");// and (250 = ReceiveResponse) and
ReceiveResponse;
SendCommand("mail from: " + From);// and (250 = ReceiveResponse) and
ReceiveResponse;
SendCommand("rcpt to: " + Receiver);// and (250 = ReceiveResponse) and
ReceiveResponse;
SendCommand("data");// and (354 = ReceiveResponse) and
ReceiveResponse;
SendCommand(Text + #13#10+".");// and (250 = ReceiveResponse) and
ReceiveResponse;
SendCommand("quit");// and (250 = ReceiveResponse);
finally
closesocket(S);
end;
finally
WSACleanup;
end;
end;

begin
writeln("Started");
SendMail("<bwgblackraven@narod.ru>", "<bwgblackraven@narod.ru>", "Date: "+
DateTimeToStr(now)+#13#10+"From: one@prog.ru"+#13#10+
"To: <bwgblackraven@narod.ru>"+#13#10+"Subject: Mail"+
#13#10#13#10+"The test", "smtp.narod.ru");
writeln("Sended");
readln;
end.


Получил такой пинок:

220
550
503
503
503
550


По RFC 503 - Bad sequence of commands

И что не верно?


 
BWG   (2002-01-17 14:27) [10]

Смена сервера на smtp.yandex.ru не помогла. Хотя он авторизации точно не требует.


 
Polevi   (2002-01-17 14:31) [11]

Ты пробовал тоже самое сделать телнетом ?


 
BWG   (2002-01-17 16:11) [12]

Что "то же самое"?


 
paul_shmakov   (2002-01-17 16:22) [13]

503 - это уже после. главное здесь 550

550 Requested action not taken: mailbox unavailable
[E.g., mailbox not found, no access]

к сожалению, почему-то у меня сейчас не получается соединиться telnet-ом ни с smtp.narod.ru, ни с smtp.yandex.ru - толи сервера висят, толи файервол у нас не пускает, хотя с smtp.mail.ru все нормально.


 
BWG   (2002-01-17 16:31) [14]

Все Яндекс к фене полетел...


 
paul_shmakov   (2002-01-17 16:37) [15]

2 BWG © (17.01.02 16:11)

Что "то же самое"?
подключиться telnet-ом к smtp.narod.ru на 25 порт и ввести вручную все команды (перед этим не забудьте включить Local Echo в Terminal/Preferences).
ваш возможный диалог с сервером я уже приводил чуть выше (paul_shmakov © (17.01.02 13:45)).
если руками все это получиться, то и программно все должно работать.




 
BWG   (2002-01-17 17:06) [16]

Не пойму чего-то. То ли получается, то ли нет. Может у меня ручки кривые.
Попробуйте, please, кто-нибудь вышеуказанный BWG © (17.01.02 14:24) код и намыльте о результатах. Не работает он у меня.
И телнет говорит " 550" когда я mail from отправляю.
Прочитайте мне, please, manual.

С уважением, Алексей.


 
Bachin   (2002-01-17 18:02) [17]

Уменя такой диалог. Только не пойму, где он пустую команду откопал :(

220 profix.kiev.ua ESMTP Sendmail 8.12.1/8.12.1; Thu, 17 Jan 2002 16:59:17 +0200 (EET)
helo delphimail
250 profix.kiev.ua Hello bachin.profix.com [196.1.4.13], pleased to meet you
mail from: <bachin@prifix.kiev.ua>
250 2.1.0 <bachin@prifix.kiev.ua>... Sender ok
rcpt to: <bachin@usb.kherson.ua>
250 2.1.5 <bachin@usb.kherson.ua>... Recipient ok
data
354 Enter mail, end with "." on a line by itself
test message
.

250 2.0.0 g0HExHVN029445 Message accepted for delivery
quit
500 5.5.1 Command unrecognized: ""
FALSE


 
paul_shmakov   (2002-01-17 18:33) [18]

2 Bachin:
все нормально, вот только что-то он на quit ругнулся (???)
а в остальном все именно так и должно быть


 
BWG   (2002-01-17 21:50) [19]

Ладно.
Пошел разбираться.


 
BWG   (2002-01-18 20:50) [20]

Заставить работать Яндекс ( smtp.yandex.ru port 25) удалось. Отправил все без вопросов. Этот код - ни в какую не хочет работать!


 
BWG   (2002-01-19 12:10) [21]

Кстати: подскажите хороший Telnet-клиент (F reeware).


 
Anatoly Podgoretsky   (2002-01-19 19:14) [22]

Start|Run|Telnet


 
BWG   (2002-01-19 19:29) [23]

2 Anatoly Podgoretsky © (19.01.02 19:14) Это хороший, да? Я даже оттуда лог не могу скопировать!

Так вот, повторяю свою мысль. По словам Павла Шумакова если с помощью телнета удалось подулючиться - значит и код будет работать. С помощью телнета подключиться удалось. Код - ни в какую!

Помогите!!!


 
Anatoly Podgoretsky   (2002-01-19 21:48) [24]

Для того что бы сказать хороший или нет сперва надо дать определение этого. Меня в большинстве случаев устраивает, в некоторых других я использую TereTerm, но чаще именно первый.


 
Ghost.   (2002-01-19 21:55) [25]

Вообще 550 озачает, что почтовый ящик недоступен..ты навертное это знаешь и без меня, а на счет телнета мысль очень хорошая я тоже так делал...когда отпртавлял через маил ру и только с помощью телнета разобрался, чо если отправляешь не с их ящика или не на их ящик север возращает ошибку 553 и оказалось, что если ввести любой адрес (чужой) но их сертвера все пройдет нормально и получатель получит письмо с левого ящика..попробуй телетом всю тртанзакцию провести


 
paul_shmakov   (2002-01-20 01:56) [26]

2 BWG:
Так вот, повторяю свою мысль. По словам Павла Шумакова если с помощью телнета
Шмаков я :)

удалось подулючиться - значит и код будет работать. С помощью телнета подключиться удалось. Код - ни в какую!

ну запустите под отладчиком и оттрассируйте. код делает (должен делать) именно то, что и человек, набирающий команды в окне telnet-терминала.
код вполне может глючить - я его за пару минут написал специально для ответа на Ваш вопрос.


 
BWG   (2002-01-20 08:31) [27]

Хорошо, хорошо.
Сейчас полностью оттестирую и тогда выложу все результаты.



Страницы: 1 вся ветка

Форум: "WinAPI";
Текущий архив: 2002.03.18;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.52 MB
Время: 0.005 c
1-57437
olookin
2002-03-02 13:21
2002.03.18
И по поводу вызова процедур и функций


14-57511
KvORubinX
2002-02-04 22:17
2002.03.18
RX_LIB 275


6-57478
SemFLY
2002-01-02 17:55
2002.03.18
Компонент Winshoes ?!


1-57348
iea
2002-03-04 11:02
2002.03.18
Как обновить содержимое Form2 из Form1


3-57327
Quaker
2002-02-19 11:24
2002.03.18
Ошибки Oracle





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский