san7667 писал(а):Добрый день, подскажите пожалуйста кто  знает, живой действующий пример отправки сообщения на почту email самый простой..
какой-нибудь алгоритм или процедуру.
Неожиданно для себя тоже не нашел в интернете актуальных примеров на free pascal отправки простого почтового сообщения по smtp без использования TLS.
Написал простой кроссплатформенный пример на чистом fcl (без использования Indy, Synapse и тп.), так как все необходимое есть и хорошо работает очень давно.
Компилировал и проверял под Windows 10 и под Linux Mint (Ubuntu).
- Код: Выделить всё
- program socketmail;
 
 {$mode objfpc}{$H+}
 
 uses
 sockets, // работа с Sockets
 resolve, // Преобразование доменных имен в IP адреса и обратно с помощью DNS
 base64; // base64 кодирование/декодирование
 
 function SendMail(const SmtpServer, SenderEmail, Password, RecipientEmail, MailSubject, MailBody: string; SmtpPort: Integer): Boolean;
 var
 CSocket: TSocket;
 Address: TInetSockAddr;
 Buffer: array[0..1023] of Char;
 BytesRead: Integer;
 IPAddr: string;
 MailContent, Base64Encoded: string;
 hrs: THostResolver;
 
 procedure SendCommand(Socket: TSocket; const Command: string);
 begin
 WriteLn('Client: ', Command);
 fpsend(Socket, PChar(Command + #13#10), longword(Length(Command) + 2), 0);
 BytesRead := fprecv(Socket, @Buffer[0], SizeOf(Buffer), 0);
 Buffer[BytesRead] := #0;
 WriteLn('Server: ', Buffer);
 end;
 
 begin
 Result := False; // По умолчанию считаем, что отправка не удалась
 
 // Создание сокета
 CSocket := fpsocket(AF_INET, SOCK_STREAM, 0);
 if CSocket = -1 then
 begin
 WriteLn('Error creating socket.');
 Exit;
 end;
 
 // Преобразование доменного имени SMTP сервера в IP адрес
 hrs := THostResolver.Create(nil);
 if hrs.NameLookup(SmtpServer) then
 begin
 IPAddr := hrs.AddressAsString;
 WriteLn('Resolved IP Address: ', IPAddr);
 end
 else
 begin
 WriteLn('Failed to resolve the hostname: ', SmtpServer);
 Exit;
 end;
 
 // Подключение к SMTP серверу
 with Address do
 begin
 sin_family := AF_INET; //TCP/IP
 sin_port:= htons(word(SmtpPort)); //Порт
 sin_addr:=StrToNetAddr(hrs.AddressAsString); // IP адрес
 end;
 
 hrs.Free; // Освобождаем переменную
 
 if fpconnect(CSocket, @Address, SizeOf(Address)) < 0 then
 begin
 WriteLn('Error connecting to SMTP server.');
 Exit;
 end;
 
 // Отправка команды EHLO
 SendCommand(CSocket, 'EHLO client');
 
 // Производим аутентификацию, отправляя команды AUTH LOGIN
 SendCommand(CSocket, 'AUTH LOGIN');
 
 // Отправка логина (email отправителя) в формате Base64
 Base64Encoded := EncodeStringBase64(SenderEmail);
 if Base64Encoded = '' then
 begin
 WriteLn('Error encoding login.');
 Exit;
 end;
 SendCommand(CSocket, Base64Encoded);
 
 // Отправка пароля в формате Base64
 Base64Encoded := EncodeStringBase64(Password);
 if Base64Encoded = '' then
 begin
 WriteLn('Error encoding password.');
 Exit;
 end;
 SendCommand(CSocket, Base64Encoded);
 
 // Отправка команды MAIL FROM
 MailContent := 'MAIL FROM: <' + SenderEmail + '>';
 SendCommand(CSocket, MailContent);
 
 // Отправка команды RCPT TO
 MailContent := 'RCPT TO: <' + RecipientEmail + '>';
 SendCommand(CSocket, MailContent);
 
 // Отправка команды DATA
 SendCommand(CSocket, 'DATA');
 
 // Отправка данных письма
 MailContent :=
 'Subject: ' + MailSubject + #13#10 +
 'From: <' + SenderEmail + '>' + #13#10 +
 'To: <' + RecipientEmail + '>' + #13#10 +
 #13#10 +
 MailBody + #13#10 +
 '.';
 
 SendCommand(CSocket, MailContent);
 
 // Отправка команды QUIT
 SendCommand(CSocket, 'QUIT');
 
 // Закрытие сокета
 CloseSocket(CSocket);
 
 Result := True; // Отправка прошла успешно
 end;
 
 begin
 if SendMail('smtp.rambler.ru', 'yourlogin@rambler.ru', 'yourpassword', 'adressto@mail.com', 'Test Mail', 'This is a test email sent using sockets.', 25) then
 WriteLn('Mail sent successfully.')
 else
 WriteLn('Error sending mail.');
 end.
а также пример на чистом fcl под windows с помощью WinSock2:
- Код: Выделить всё
- program socketmail;
 
 {$mode objfpc}{$H+}
 
 uses
 WinSock, // WinSock2 Socket Library for Win32
 base64; // base64 encoder & decoder
 
 function SendMail(const SmtpServer, SenderEmail, Password, RecipientEmail, MailSubject, MailBody: string; SmtpPort: Integer): Boolean;
 var
 CSocket: TSocket;
 Address: TSockAddrIn;
 Buffer: array[0..1023] of Char;
 BytesRead: Integer;
 IPAddr: string;
 HostEnt: PHostEnt;
 Addr: TInAddr;
 WSAData: TWSAData;
 MailContent, Base64Encoded: string;
 
 procedure SendCommand(Socket: TSocket; const Command: string);
 begin
 WriteLn('Client: ', Command);
 Send(Socket, PChar(Command + #13#10), Length(Command) + 2, 0);
 BytesRead := Recv(Socket, Buffer[0], SizeOf(Buffer), 0);
 Buffer[BytesRead] := #0;
 WriteLn('Server: ', Buffer);
 end;
 
 begin
 Result := False; // По умолчанию считаем, что отправка не удалась
 
 // Инициализация WinSock
 if WSAStartup($202, WSAData) <> 0 then
 begin
 WriteLn('Error initializing WinSock.');
 Exit;
 end;
 
 // Создание сокета
 CSocket := Socket(AF_INET, SOCK_STREAM, 0);
 if CSocket = INVALID_SOCKET then
 begin
 WriteLn('Error creating socket.');
 Exit;
 end;
 
 // Преобразование доменного имени SMTP сервера в IP адрес
 HostEnt := gethostbyname(PChar(SmtpServer));
 if HostEnt <> nil then
 begin
 Addr := PInAddr(HostEnt^.h_addr_list^)^;
 IPAddr := inet_ntoa(Addr);
 end
 else
 begin
 WriteLn('Host not found: ' + SmtpServer);
 Exit;
 end;
 
 // Подключение к SMTP серверу
 Address.sin_family := AF_INET;
 Address.sin_port := htons(u_short(SmtpPort));
 Address.sin_addr.s_addr := inet_addr(PChar(IPAddr));
 
 if connect(CSocket, Address, SizeOf(Address)) < 0 then
 begin
 WriteLn('Error connecting to SMTP server.');
 Exit;
 end;
 
 // Отправка команды EHLO
 SendCommand(CSocket, 'EHLO client');
 
 // Производим аутентификацию, отправляя команды AUTH LOGIN
 SendCommand(CSocket, 'AUTH LOGIN');
 
 // Отправка логина (email отправителя) в формате Base64
 Base64Encoded := EncodeStringBase64(SenderEmail);
 if Base64Encoded = '' then
 begin
 WriteLn('Error encoding login.');
 Exit;
 end;
 SendCommand(CSocket, Base64Encoded);
 
 // Отправка пароля в формате Base64
 Base64Encoded := EncodeStringBase64(Password);
 if Base64Encoded = '' then
 begin
 WriteLn('Error encoding password.');
 Exit;
 end;
 SendCommand(CSocket, Base64Encoded);
 
 // Отправка команды MAIL FROM
 MailContent := 'MAIL FROM: <' + SenderEmail + '>';
 SendCommand(CSocket, MailContent);
 
 // Отправка команды RCPT TO
 MailContent := 'RCPT TO: <' + RecipientEmail + '>';
 SendCommand(CSocket, MailContent);
 
 // Отправка команды DATA
 SendCommand(CSocket, 'DATA');
 
 // Отправка данных письма
 MailContent :=
 'Subject: ' + MailSubject + #13#10 +
 'From: <' + SenderEmail + '>' + #13#10 +
 'To: <' + RecipientEmail + '>' + #13#10 +
 #13#10 +
 MailBody + #13#10 +
 '.';
 
 SendCommand(CSocket, MailContent);
 
 // Отправка команды QUIT
 SendCommand(CSocket, 'QUIT');
 
 // Закрытие сокета
 CloseSocket(CSocket);
 
 // Очистка WinSock
 WSACleanup;
 
 Result := True; // Отправка прошла успешно
 end;
 
 begin
 if SendMail('smtp.rambler.ru', 'yourlogin@rambler.ru', 'yourpassword', 'adressto@mail.com', 'Test Mail', 'This is a test email sent using sockets.', 25) then
 WriteLn('Mail sent successfully.')
 else
 WriteLn('Error sending mail.');
 end.
Оба примера отлично отправляют сообщения на любые адреса через почту Rambler.
По поводу мнений о том, что все крупные почтовые сервисы требуют безопасного подключения по smtp, зарегистрировал бесплатный ящик на 
Rambler, в помощи  
написано, что подключение по smtp может осуществляться на smtp.rambler.ru в том числе без шифрования. Главное, не забыть включить в настройках почты переключатель "Доступ к почтовому ящику с помощью почтовых клиентов."
Тестовые сообщения успешно отправляются на любые адреса.
Понятно, что это просто пример, но он позволяет понять "кухню" изнутри...
При необходимости, можно расширить для отправки вложений и т.п., добавить обработку ответов с сервера.
Если нужен позарез TLS, то можно конечно заморочиться с 
Schannel (MS SSPI SSL), но OpenSSL будет гораздо проще, ценой двух dll в папке с программой.
Приведенные примеры сделаны в процедурном стиле с помощью модуля 
sockets из состава rtl, если требуется объектно-ориентрованный подход, то можно использовать надстройку над sockets (для windows она использует winsock) из состава fpc-net модуль 
sscockets.
Модуль "sockets" из состава RTL (Run-Time Library) и модуль "ssockets" из состава FCL-Net (Free Component Library for Network) предоставляют функциональность для работы с сокетами. Однако есть некоторые различия между ними:
1. Модуль "sockets" из состава RTL:
    - Этот модуль предоставляет базовые функции для работы с сокетами, которые являются стандартными для языка Free Pascal.
    - Включает простые процедуры и функции для создания, связывания, прослушивания и подключения сокетов.
    - Модуль "sockets" предоставляет сокеты на низком уровне, что означает, что вам придется самостоятельно управлять деталями работы с сокетами, такими как настройка соединения и обработка данных.
2. Модуль "ssockets" из состава FCL-Net:
    - Этот модуль также предоставляет функции для работы с сокетами, но на более высоком уровне абстракции.
    - Включает классы и компоненты для работы с сетевыми протоколами, такими как TCP и UDP, а также предоставляет удобные методы для обмена данными.
    - Модуль "ssockets" предоставляет более удобный и объектно-ориентированный интерфейс, что делает код более читаемым и позволяет сосредотачиваться на бизнес-логике, а не на низкоуровневых деталях работы с сокетами.
Основное различие между модулем "sockets" из RTL и модулем "ssockets" из FCL-Net заключается в уровне абстракции и удобстве использования. Модуль "sockets" предоставляет базовую функциональность на низком уровне, в то время как модуль "ssockets" абстрагирует сложности работы с сокетами и предоставляет более удобный интерфейс для программистов, что облегчает создание сетевых приложений на Free Pascal.
В ходе изысканий использовал 
smtp4dev  - фейковый smtp email server для разработки и тестирования
Наткнулся на интересный 
набор маленьких утилит для отправки почты, в том числе из консоли
И попалась интересная программа 
Stunnel - прокси, предназначенная для добавления функциональности TLS кодирования для существующих клиентов и серверов, без изменения их кода.
Ну и как еще одно решение - использование smtp релея, своего или стороннего.