I was looking for an implementation for sending letters via smtp, I did not find any documentation, I had to wander around the forums, but nowhere was there anything practical. I found a topic on the forum http://www.cyberforum.ru/cpp-beginners/thread1020524 ... from 2012, I did it by analogy, but I did not achieve anything.

In short, here's the code:

#define _CRT_SECURE_NO_WARNINGS #pragma comment (lib,"Ws2_32.lib") #include <windows.h> #include <winsock.h> #include <stdio.h> WSADATA ws; SOCKET s; struct sockaddr_in addr; hostent* d_addr; char text[1024]; int main() { // ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ сокСты if (FAILED(WSAStartup(MAKEWORD(1, 1), &ws))) { printf("Error in WSAStartup(...)\n"); return 1; } // создаСм сокСт s = socket(AF_INET, SOCK_STREAM, 0); if (s == INVALID_SOCKET) { printf("Error in socket(...)\n"); return 1; } // ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ адрСс сСрвСра d_addr = gethostbyname("smtp.gmail.com"); if (d_addr == NULL) { printf("Error in gethostbyname(...)\n"); return 1; }; // заполняСм ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ адрСса addr.sin_family = AF_INET; addr.sin_addr.s_addr = *((unsigned long*)d_addr->h_addr); addr.sin_port = htons(465); // устанавливаСм соСдинСниС if (SOCKET_ERROR == (connect(s, (sockaddr*)& addr, sizeof(addr)))) { printf("Error in connect(...)\n"); return 1; } // ΠΆΠ΄Π΅ΠΌ ΠΎΡ‚Π²Π΅Ρ‚ ΠΎΡ‚ сСрвСра recv(s, text, sizeof(text), 0); printf("recv - %s", text); // привСтствуСм сСрвСр strcpy(text, "EHLO SSL\r\n"); send(s, text, strlen(text), 0); printf("send - %s", text); // ΠΆΠ΄Π΅ΠΌ ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΎΡ‚ сСрвСра recv(s, text, sizeof(text), 0); printf("recv - %s", text); // Π½Π°Ρ‡ΠΈΠ½Π°Π΅ΠΌ ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚ состоящий ΠΈΠ· ΠΏΠΎΠ»Π΅ΠΉ // MAIL FROM: ΠΈ RCPT TO: ПослС ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ поля ΠΆΠ΄Π΅ΠΌ // ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½ΠΈΠ΅ strcpy(text, "AUTH LOGIN\r\n"); send(s, text, strlen(text), 0); printf("send - %s", text); recv(s, text, sizeof(text), 0); printf("recv - %s", text); // сообщаСм отправитСля strcpy(text, "MAIL FROM: [email]sender@mail.ru[/email] "); send(s, text, strlen(text), 0); printf("send - %s", text); // ΠΆΠ΄Π΅ΠΌ ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΎΡ‚ сСрвСра recv(s, text, sizeof(text), 0); printf("recv - %s", text); // сообщаСм получатСля strcpy(text, "RCPT TO: [email]receiver@mtu-net.ru[/email] "); send(s, text, strlen(text), 0); printf("send - %s", text); // ΠΆΠ΄Π΅ΠΌ ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΎΡ‚ сСрвСра recv(s, text, sizeof(text), 0); printf("recv - %s", text); // ΠΏΠΎΠ΄Π°Π΅ΠΌ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ, Ρ‡Ρ‚ΠΎ Π³ΠΎΡ‚ΠΎΠ²Ρ‹ Π½Π°Ρ‡Π°Ρ‚ΡŒ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Ρƒ письма strcpy(text, "DATA\r\n"); send(s, text, strlen(text), 0); printf("send - %s", text); // ΠΆΠ΄Π΅ΠΌ ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΎΡ‚ сСрвСра recv(s, text, sizeof(text), 0); printf("recv - %s", text); // ΠΏΠ΅Ρ€Π΅Π΄Π°Π΅ΠΌ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ // ΠΎΡ‚ ΠΊΠΎΠ³ΠΎ письмо strcpy(text, "FROM: [email]sender@mail.ru[/email] "); send(s, text, strlen(text), 0); printf("send - %s", text); // ΠΊΠΎΠΌΡƒ письмо strcpy(text, "TO: [email]receiver@mtu-net.ru[/email] "); send(s, text, strlen(text), 0); printf("send - %s", text); // Ρ‚Π΅ΠΌΠ° письма strcpy(text, "SUBJECT: test\r\n"); send(s, text, strlen(text), 0); printf("send - %s", text); // тСкст письма strcpy(text, "Hi!\nIt is a message for you\n"); send(s, text, strlen(text), 0); printf("send - %s", text); // Π³ΠΎΠ²ΠΎΡ€ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Π·Π°ΠΊΠΎΠ½Ρ‡ΠΈΠ»ΠΈ strcpy(text, "\r\n.\r\n"); send(s, text, strlen(text), 0); printf("send - %s", text); recv(s, text, sizeof(text), 0); printf("recv - %s", text); // прощаСмся с сСрвСром strcpy(text, "QUIT"); send(s, text, strlen(text), 0); printf("send - %s", text); // Π·Π°ΠΊΡ€Ρ‹Π²Π°Π΅ΠΌ сокСт closesocket(s); return 0; } 

He seems to be working, through the 25th port and 587 the connection passes. But at the time of authorization request, the server generates an error that does not use encryption. As I understand it, this is due to the fact that I use a port that does not support encryption. According to the documentation, such a port is 465, but when I set it up, the server connects for a long time and as a result does not respond, that is, with empty messages, although there seems to be a connection.

Here is a picture at port 465:

recv - send - EHLO SSL recv - EHLO SSL send - AUTH LOGIN recv - AUTH LOGIN send

  • MAIL FROM: sender@mail.ru recv - MAIL FROM: sender@mail.ru send - RCPT TO: receiver@mtu-net.ru recv - RCPT TO: receiver@mtu-net.ru send
  • DATA recv - DATA send - FROM: sender@mail.ru send - TO: receiver@mtu-net.ru send - SUBJECT: test send - Hi! It is a message for you send. recv -. send - QUIT

Here is such for others:

recv - 220 smtp2o.mail.yandex.net ESMTP (Want to use Yandex.Mail for your domain? Visit http://pdd.yandex.ru ) send - EHLO SSL recv - 250-smtp2o.mail.yandex.net 250- 8BITMIME 250-PIPELINING 250-SIZE 42991616 250-STARTTLS 250-AUTH LOGIN PLAIN XOAUTH2 250-DSN 250 ENHANCEDSTATUSCODES send - AUTH LOGIN recv-530 Please see: http://help.yandex.ru/mail/mail-clients/ssl.xml

250 ENHANCEDSTATUSCODES send - MAIL FROM: sender@mail.ru recv - MAIL FROM: sender@mail.ru send - RCPT TO: receiver@mtu-net.ru recv - RCPT TO: receiver@mtu-net.ru send - DATA recv - DATA send - FROM: sender@mail.ru send - TO: receiver@mtu-net.ru send - SUBJECT: test send - Hi! It is a message for you send. recv -. send - QUIT

I do not know what to do, I will be grateful if you help.

  • It is necessary to establish an encrypted connection via TLS - VTT
  • Gmail, even 8-9 years ago, did not have the ability to use smtp without encryption, so your version on raw sockets will not work with gmail (I would work with mail ru in 2012, perhaps. I received a second year course with mail from rambler on raw sockets without encryption send message). - vegorov
  • Is it possible to encrypt the connection with the language? without additional curl - type libraries - m3iz
  • It is possible without curl, but then I recommend installing the openSSL library, in any case, you will need it, even if you install curl, to support encryption protocols, it will require openSSL. - Alexey Nikolaev

1 answer 1

I advise you to use the libcurl library: https://curl.haxx.se/libcurl/c/smtp-mail.html

 #include <stdio.h> #include <string.h> #include <curl/curl.h> /* * For an SMTP example using the multi interface please see smtp-multi.c. */ /* The libcurl options want plain addresses, the viewable headers in the mail * can very well get a full name as well. */ #define FROM_ADDR "<sender@example.org>" #define TO_ADDR "<addressee@example.net>" #define CC_ADDR "<info@example.org>" #define FROM_MAIL "Sender Person " FROM_ADDR #define TO_MAIL "A Receiver " TO_ADDR #define CC_MAIL "John CC Smith " CC_ADDR static const char *payload_text[] = { "Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n", "To: " TO_MAIL "\r\n", "From: " FROM_MAIL "\r\n", "Cc: " CC_MAIL "\r\n", "Message-ID: <dcd7cb36-11db-487a-9f3a-e652a9458efd@" "rfcpedant.example.org>\r\n", "Subject: SMTP example message\r\n", "\r\n", /* empty line to divide headers from body, see RFC5322 */ "The body of the message starts here.\r\n", "\r\n", "It could be a lot of lines, could be MIME encoded, whatever.\r\n", "Check RFC5322.\r\n", NULL }; struct upload_status { int lines_read; }; static size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp) { struct upload_status *upload_ctx = (struct upload_status *)userp; const char *data; if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) { return 0; } data = payload_text[upload_ctx->lines_read]; if(data) { size_t len = strlen(data); memcpy(ptr, data, len); upload_ctx->lines_read++; return len; } return 0; } int main(void) { CURL *curl; CURLcode res = CURLE_OK; struct curl_slist *recipients = NULL; struct upload_status upload_ctx; upload_ctx.lines_read = 0; curl = curl_easy_init(); if(curl) { /* This is the URL for your mailserver */ curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com"); /* Note that this option isn't strictly required, omitting it will result * in libcurl sending the MAIL FROM command with empty sender data. All * autoresponses should have an empty reverse-path, and should be directed * to the address in the reverse-path which triggered them. Otherwise, * they could cause an endless loop. See RFC 5321 Section 4.5.5 for more * details. */ curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM_ADDR); /* Add two recipients, in this particular case they correspond to the * To: and Cc: addressees in the header, but they could be any kind of * recipient. */ recipients = curl_slist_append(recipients, TO_ADDR); recipients = curl_slist_append(recipients, CC_ADDR); curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); /* We're using a callback function to specify the payload (the headers and * body of the message). You could just use the CURLOPT_READDATA option to * specify a FILE pointer to read from. */ curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source); curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); /* Send the message */ res = curl_easy_perform(curl); /* Check for errors */ if(res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); /* Free the list of recipients */ curl_slist_free_all(recipients); /* curl won't send the QUIT command until you call cleanup, so you should * be able to re-use this connection for additional messages (setting * CURLOPT_MAIL_FROM and CURLOPT_MAIL_RCPT as required, and calling * curl_easy_perform() again. It may not be a good idea to keep the * connection open for a very long time though (more than a few minutes * may result in the server timing out the connection), and you do want to * clean up in the end. */ curl_easy_cleanup(curl); } return (int)res; }