Отправка почты с помощью ARDUINO.

В этом посте я представлю вашему вниманию две библиотеки для отправки почты с ардуино. Все началось с того, что мне понадобилось отправлять некоторые данные с ардуино при наступлении определенного события. Рассматривался вариант отправки СМС с SIM900, но СМСки платные, а интернет все равно оплачен и к тому-же, на любом смартфоне есть возможность принимать почту. Таким образом я остановился на почте. Отправка почты с ардуино оказалась делом не сложным. Однако выяснилось что все крупные монополисты в области почты (Яндекс, Гуголь и Мэйл) перешли на защищенные TLS соединения (в целях обеспечения вашей безопасности…:). К сожалению простая ардуинка не может устанавливать такие соединения в виду малого количества памяти. В связи с этим, для отправки почты с ардуино я решил поискать хостеров предоставляющих за разумные деньги почтовый хостинг с возможностью отправки почты по открытому каналу. Таких нашлось не мало. 10 ящиков + 1ГБ места + домен от одного из таких хостеров на год мне обошлись в 600 руб, что я думаю не очень большие деньги. Проверив возможность отправки почты через telnet я приступил к написанию библиотеки. Сразу оговорюсь что я не очень люблю беспроводные технологии, а больше уважаю провода. Поэтому библиотеки написаны под шилд Ethernet Shield W5100 и ему подобные использующие в своей работе библиотеку Ethernet. Обе библиотеки написаны без Delay() и не замедляют работу контроллера.


Итак, первая библиотека для отправки почты с помощью arduino – SimpleMail. Она требует от пользователя минимум знаний в области программирования, логин и пароль указываются стандартным способом. Далее, используя стороннюю библиотеку rBase64, логин и пароль кодируются по алгоритму Base64 для обеспечения авторизации. В PROGMEM упрятаны только только команды серверу. Исходя из вышесказанного данная библиотека отъедает прилично оперативки, но для тех кому это не принципиально – пойдет. Отправка письма осуществляется передачей в метод sendMail строк с указанными параметрами.


Вторая библиотека AdvancedMail в настройке сложнее. Все что можно: команды серверу, настройки сервера, логины, пароли, темы, сообщения и адреса хранятся в PROGMEM. Пароли и логины необходимо сначала закодировать по алгоритму Base64 сторонними способами. Сейчас в сети много онлайн-сервисов позволяющих это сделать. Например base64.ru. После этого закодированные строки необходимо вставить в файл .cpp библиотеки. Таким образом мы сильно экономим драгоценную оперативку. В библиотеке AdvancedMail для отправки почты с ардуино есть заготовки под 3 ящика, 3х адресатов, 5ти тем и 10 сообщений. Если вам необходимо больше – дописывайте. Отправка письма осуществляется передачей в метод sendMail интов с номером ящика, адреса, темы и сообщения.


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

Чуть позднее запишу видео с демонстрацией работы библиотек.
Если есть вопросы – пишите в комментариях.
Пожалуйста не поленитесь и оцените пост!

Библиотека SimpleMail для отправки почты с ARDUINO

Страница библиотеки

Текущая версия: 0.0.1 / 2018.12.12
Предыдущие версии:

Size: 8 KB
Version: 0.0.1

Библиотека AdvancedMail для отправки почты с ARDUINO

Страница библиотеки

Текущая версия: 0.0.1 / 2018.12.12
Предыдущие версии:

Size: 6 KB
Version: 0.0.1



SimpleMail.h

  1. #ifndef SimpleMail_h
  2. #define SimpleMail_h
  3.  
  4. #include "Arduino.h"
  5. #include "Ethernet.h"
  6. #include "rBase64.h"
  7. #include <avr\pgmspace.h>
  8.  
  9. class SimpleSmtpClient {
  10. public:
  11.     SimpleSmtpClient();
  12.     bool sendMail(  char * smtpServer, uint16_t port, char * username, char * password, char * mailfrom, char * mailto, char * subject, char * message);
  13.     /* sendMail(  char * smtpServer, uint16_t port, char * username, char * password, char * mailfrom, char * mailto, char * subject, char * message);
  14.        Соединяется с сервером, пытатеся отправить письмо
  15.  
  16.        Принимаемые параметы:
  17.         char * smtpServer - адрес сервера,
  18.         uint16_t port - порт сервера,
  19.         char * username - логин,
  20.         char * password - пароль,
  21.         char * mailfrom - адрес отправителя,
  22.         char * mailto - адрес получателя,
  23.         char * subject - тема письма,
  24.         char * message - текст сообщения
  25.  
  26.         Возвращаемые значения:
  27.         false - идет отправка письма
  28.         true - попытка отправки завершена. Статус отправки проверяется методом getStatus()
  29.     */
  30.     bool getStatus();
  31.     /* getStatus() статус завершенного сеанса отправки письма
  32.         Возвращаемые значения:
  33.         false - сеанс завершен с ошибкой, письмо не отправлено
  34.         true - сеанс завершен успешно, письмо отправлено
  35.     */
  36. private:
  37.    /*Команды передаваемые серверу сохранены в PROGMEM для экономии оперативной памяти*/
  38.     static const char COMMAND_EHLO[]        PROGMEM;
  39.     static const char COMMAND_AUTHLOGIN[]   PROGMEM;
  40.     static const char COMMAND_MAILFROM[]    PROGMEM;
  41.     static const char COMMAND_MAILTO[]      PROGMEM;
  42.     static const char COMMAND_DATA[]        PROGMEM;
  43.     static const char COMMAND_SUBJECT[]     PROGMEM;
  44.     static const char COMMAND_TO[]          PROGMEM;
  45.     static const char COMMAND_QUIT[]        PROGMEM;
  46.  
  47.  
  48.  
  49.     EthernetClient  _client;
  50.     char _responseCode[3];
  51.     bool _status;
  52.     bool readResponse ();
  53.     void closeConnection(uint8_t * p_processStatus, bool status);
  54. };
  55.  
  56. #endif

SimpleMail.cpp


  1. #include "SimpleMail.h"
  2. //#define NDBG // если лог не нужен - раскомментировать стоку
  3. SimpleSmtpClient::SimpleSmtpClient(){}
  4.  
  5. bool SimpleSmtpClient::sendMail(
  6.                           char * smtpServer,
  7.                           uint16_t port,
  8.                           char * username,
  9.                           char * password,
  10.                           char * mailfrom,
  11.                           char * mailto,
  12.                           char * subject,
  13.                           char * message)
  14.                           {
  15.     static uint8_t processStatus = 0;
  16.    if (!_client.connected()){
  17.         if (_client.connect(smtpServer, port)){
  18.             #ifndef NDBG
  19.             Serial.println(F("SimpleMail >> SMTP client connected"));
  20.             #endif // NDBG
  21.         }
  22.         else {
  23.             #ifndef NDBG
  24.             Serial.println(F("SimpleMail >> SMTP client connection failed"));
  25.             #endif // NDBG
  26.         }
  27.     }
  28.     else{
  29.         switch (processStatus){
  30.             case 0:
  31.                 if (readResponse ()){
  32.                 if(atoi(_responseCode) == 220 || atoi(_responseCode) == 221 ){
  33.                     char buff[14];
  34.                     strcpy_P(buff, COMMAND_EHLO);
  35.                     _client.println(buff);
  36.                     processStatus = 1;
  37.                 }
  38.                 else{
  39.                     closeConnection(&processStatus, false);
  40.                     return true;
  41.                 }
  42.             }
  43.             break;
  44.             case 1:
  45.                 if (readResponse ()){
  46.                 if(atoi(_responseCode) == 250){
  47.                     char buff[10];
  48.                     strcpy_P(buff, COMMAND_AUTHLOGIN);
  49.                     _client.println(buff);
  50.                     processStatus = 2;
  51.                 }
  52.                 else{
  53.                     closeConnection(&processStatus, false);
  54.                     return true;
  55.                 }
  56.             }
  57.             break;
  58.             case 2:
  59.                 if (readResponse ()){
  60.                 if(atoi(_responseCode) == 334){
  61.                     rbase64.encode(username);
  62.                     _client.println(rbase64.result());
  63.                     processStatus = 3;
  64.                 }
  65.                 else{
  66.                     /*closeConnection(&processStatus, false);
  67.                     return true;*/
  68.                 }
  69.             }
  70.             case 3:
  71.                 if (readResponse ()){
  72.                 if(atoi(_responseCode) == 334){
  73.                     rbase64.encode(password);
  74.                     _client.println(rbase64.result());
  75.                     processStatus = 4;
  76.                 }
  77.                 else{
  78.                     closeConnection(&processStatus, false);
  79.                     return true;
  80.                 }
  81.             }
  82.             break;
  83.             case 4:
  84.                 if (readResponse ()){
  85.                 if(atoi(_responseCode) == 235){
  86.                     char buff[10];
  87.                     strcpy_P(buff, COMMAND_MAILFROM);
  88.                     _client.print(buff);
  89.                     _client.println(mailfrom);
  90.                     processStatus = 5;
  91.                 }
  92.                 else{
  93.                     closeConnection(&processStatus, false);
  94.                     return true;
  95.                 }
  96.             }
  97.             break;
  98.             case 5:
  99.                 if (readResponse ()){
  100.                 if(atoi(_responseCode) == 250){
  101.                     char buff[8];
  102.                     strcpy_P(buff, COMMAND_MAILTO);
  103.                     _client.print(buff);
  104.                     _client.println(mailto);
  105.                     processStatus = 6;
  106.                 }
  107.                 else{
  108.                     closeConnection(&processStatus, false);
  109.                     return true;
  110.                 }
  111.             }
  112.             break;
  113.             case 6:
  114.                 if (readResponse ()){
  115.                 if(atoi(_responseCode) == 250){
  116.                     char buff[8];
  117.                     strcpy_P(buff, COMMAND_DATA);
  118.                     _client.println(buff);
  119.                     processStatus = 7;
  120.                 }
  121.                 else{
  122.                     closeConnection(&processStatus, false);
  123.                     return true;
  124.                 }
  125.             }
  126.             break;
  127.             case 7:
  128.                 if (readResponse ()){
  129.                 if(atoi(_responseCode) == 354){
  130.                     {   char buff[3];
  131.                         strcpy_P(buff, COMMAND_TO);
  132.                         _client.print(buff);
  133.                     }
  134.                     _client.println(mailto);
  135.                     {   char buff[8];
  136.                         strcpy_P(buff, COMMAND_SUBJECT);
  137.                         _client.print(buff);
  138.                     }
  139.                     _client.println(subject);
  140.                     _client.println();
  141.                     _client.println(message);
  142.                     _client.println(F("."));
  143.                     processStatus = 8;
  144.                 }
  145.                 else{
  146.                     closeConnection(&processStatus, false);
  147.                     return true;
  148.                 }
  149.             }
  150.             break;
  151.             case 8:
  152.                 if (readResponse ()){
  153.                 if(atoi(_responseCode) == 250){
  154.                     char buff[4];
  155.                     strcpy_P(buff, COMMAND_QUIT);
  156.                     _client.println(buff);
  157.                     processStatus = 9;
  158.  
  159.                 }
  160.                 else{
  161.                     closeConnection(&processStatus, false);
  162.                     return true;
  163.                 }
  164.             }
  165.             break;
  166.             case 9:
  167.                 if (readResponse ()){
  168.                     if(atoi(_responseCode) == 221){
  169.                     closeConnection(&processStatus, true);
  170.                     return true;
  171.                     }
  172.                 }
  173.             break;
  174.             default:
  175.                 Serial.println(F("Zombies rising!"));
  176.         }
  177.     }
  178.     return false;
  179. };
  180.  
  181. bool SimpleSmtpClient::readResponse (){
  182.     if (_client.available()) {
  183.         static uint8_t n = 0;
  184.         #ifndef NDBG
  185.         if (!n) Serial.print(F("SMTP SERVER >>"));
  186.         #endif // NDBG
  187.         if (n < 3){
  188.             char sym = _client.read();
  189.             _responseCode[n] = sym;
  190.             #ifndef NDBG
  191.             Serial.print(sym);
  192.             #endif // NDBG
  193.             n++;
  194.             return false;
  195.         }
  196.         else {
  197.             char sym = _client.read();
  198.             #ifndef NDBG
  199.             Serial.print(sym);
  200.             #endif // NDBG
  201.             if (sym == 0x0A){
  202.                 n = 0;
  203.                 return true;
  204.             }
  205.             return false;
  206.         }
  207.     }
  208.     else {
  209.         return false;
  210.     }
  211. };
  212. void SimpleSmtpClient::closeConnection(uint8_t * p_processStatus, bool status){
  213.     * p_processStatus = 0;
  214.     _client.flush();
  215.     _client.stop();
  216.     #ifndef NDBG
  217.     if(!_client.connected()) {
  218.         Serial.println();
  219.         if (status) Serial.println(F("SimpleMail >> NO error detected"));
  220.         else Serial.println(F("SimpleMail >> Error detected"));
  221.         Serial.println(F("SimpleMail >> SMTP client disconnected"));
  222.     }
  223.     #endif // NDBG
  224.     _status = status;
  225. };
  226. bool SimpleSmtpClient::getStatus(){return _status;};
  227. /**-----------------Команды серверу-----------------*/
  228. const char SimpleSmtpClient::COMMAND_EHLO[] = "EHLO 127.0.0.1";
  229. const char SimpleSmtpClient::COMMAND_AUTHLOGIN[] = "AUTH LOGIN";
  230. const char SimpleSmtpClient::COMMAND_MAILFROM[] = "MAIL From:";
  231. const char SimpleSmtpClient::COMMAND_MAILTO[] = "RCPT To:";
  232. const char SimpleSmtpClient::COMMAND_DATA[] = "DATA";
  233. const char SimpleSmtpClient::COMMAND_SUBJECT[] = "Subject:";
  234. const char SimpleSmtpClient::COMMAND_TO[] = "To:";
  235. const char SimpleSmtpClient::COMMAND_QUIT[] = "QUIT";

Пример использования

  1. #include <SPI.h>// подключаем библиотеку SPI
  2. #include <Ethernet.h>// подключаем библиотеку Ethernet
  3. #include <SimpleMail.h>// подключаем библиотеку SimpleMail
  4.  
  5. uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };// задаем MAKадрес
  6. IPAddress ip(192, 168, 0, 77);// задаем айпи адрес (проверьте чтобы была корректная подсеть и не было конфликта айпи адресов)
  7. SimpleSmtpClient client; //создаем экземпляр класса SimpleSmtpClient (клиента SMTP)
  8.  
  9. char smtpServer[] = "smtp.spaceweb.ru"; // указываем адрес сервера
  10. uint16_t port = 25; // указываем порт сервера
  11. char user[] = "sendmail@avrguard.ru"; // указываем логин
  12. char pass[] = "t7N6254Y5*y4WCV"; // указываем пароль
  13. char mailto[] = "Укажите ваш адрес получателя"; // указываем адрес получателя
  14. char mailfrom[] = "sendmail@avrguard.ru"; // указываем адрес отправителя
  15. char subject[] = "Test subject"; // указываем тему
  16. char message[] = "Test\nmessage"; // указываем текст сообщения
  17. bool flag = false;// создаем флаг для отправки письма
  18. void setup() {
  19.   Serial.begin(9600);// инициализируем Serial
  20.   Ethernet.begin(mac, ip);// инициализируем Ethernet соединение
  21.   delay(1000);
  22. }
  23. void loop() {
  24.   // put your main code here, to run repeatedly:
  25. test();
  26.  if (flag) {// если флаг есть - пытаемся отправить письмо
  27.   if (client.sendMail(smtpServer,port,user,pass,mailfrom,mailto,subject,message)) {// если сеанс закончен
  28.       flag = false;//сбрасываем флаг
  29.       if (client.getStatus()) Serial.println(F("Message sent!"));
  30.       else Serial.println(F("Message not sent!"));
  31.     }
  32.   }
  33. }
  34. void test() {
  35.   if (Serial.available()) {// при приеме из Serial знака 0 переводит flag в true для инициализации отправки письма
  36.     byte symbol = Serial.read();
  37.     if (symbol == '0') {
  38.       Serial.println(F("Try to send mail..."));
  39.       flag = true;
  40.     }
  41.   }
  42. }

AdvancedMail.h

  1. #ifndef AdvancedMail_h
  2. #define AdvancedMail_h
  3.  
  4. #include "Arduino.h"
  5. #include "Ethernet.h"
  6. #include <avr\pgmspace.h>
  7.  
  8. class AdvancedSmtpClient {
  9. public:
  10.     AdvancedSmtpClient();
  11.     bool sendMail(uint8_t boxNum, uint8_t recipientNum, uint8_t subjectNum, uint8_t messageNum);
  12.     /* sendMail(uint8_t boxNum, uint8_t recipientNum, uint8_t subjectNum, uint8_t messageNum)
  13.        Соединяется с сервером, пытатеся отправить письмо
  14.  
  15.        Принимаемые параметы:
  16.        uint8_t boxNum - номер с настройками сервера, куда входят:
  17.             SMTP_SERVER_N
  18.             PORT_N
  19.             USER_N
  20.             PASS_N
  21.             FROM_N
  22.         uint8_t recipientNum - номер адреса получателя, куда входит:
  23.             TO_N
  24.         uint8_t subjectNum - номер темы, куда входит:
  25.             SUBJECT_N
  26.         uint8_t messageNum - номер сообщения, куда входит:
  27.             MESSAGE_N
  28.  
  29.  
  30.         Возвращаемые значения:
  31.         false - идет отправка письма
  32.         true - попытка отправки завершена. Статус отправки проверяется методом getStatus()
  33.     */
  34.     bool getStatus();
  35.     /* getStatus() статус завершенного сеанса отправки письма
  36.         Возвращаемые значения:
  37.         false - сеанс завершен с ошибкой, письмо не отправлено
  38.         true - сеанс завершен успешно, письмо отправлено
  39.     */
  40. private:
  41.  
  42.  
  43. /**------------------------------Настройки почты начало--------------------------*/
  44.  
  45.     /*-----------------SMTP серверы-----------------*/
  46.     static const char SMTP_SERVER_0[]        PROGMEM;
  47.     //static const char SMTP_SERVER_1[]        PROGMEM;//раскомментируйте строку для добавления SMTP сервера 1
  48.     //static const char SMTP_SERVER_2[]         PROGMEM;//раскомментируйте строку для добавления SMTP сервера 2
  49.  
  50.     static const char * const SMTP_SERVER_SETTINGS[] PROGMEM;
  51.  
  52.     /*-----------------Порты-----------------*/
  53.     static const char PORT_0[]             PROGMEM;
  54.     //static const char PORT_1[]             PROGMEM;//раскомментируйте строку для добавления порта для сервера 1
  55.     //static const char PORT_2[]               PROGMEM;//раскомментируйте строку для добавления порта для сервера 2
  56.  
  57.     static const char * const PORT_SETTINGS[] PROGMEM;
  58.  
  59.     /*-----------------Имена пользователей-----------------*/
  60.     static const char USER_0[]               PROGMEM;
  61.     //static const char USER_1[]               PROGMEM;//раскомментируйте строку для добавления логина для сервера 1
  62.     //static const char USER_2[]               PROGMEM;//раскомментируйте строку для добавления логина для сервера 2
  63.  
  64.     static const char * const USER_SETTINGS[] PROGMEM;
  65.  
  66.     /*-----------------Пароли-----------------*/
  67.     static const char PASS_0[]               PROGMEM;
  68.     //static const char PASS_1[]               PROGMEM;//раскомментируйте строку для добавления пароля для сервера 1
  69.     //static const char PASS_2[]               PROGMEM;//раскомментируйте строку для добавления пароля для сервера 2
  70.  
  71.     static const char * const PASS_SETTINGS[] PROGMEM;
  72.  
  73.     /*-----------------От кого письмо-----------------*/
  74.     static const char FROM_0[]               PROGMEM;
  75.     //static const char FROM_1[]               PROGMEM;//раскомментируйте строку для добавления адреса для поля from сервера 1
  76.     //static const char FROM_2[]               PROGMEM;//раскомментируйте строку для добавления адреса для поля from сервера 2
  77.  
  78.     static const char * const FROM_SETTINGS[] PROGMEM;
  79.  
  80.     /*-----------------Кому письмо-----------------*/
  81.     static const char TO_0[]               PROGMEM;
  82.     //static const char TO_1[]               PROGMEM;//раскомментируйте строку для добавления адреса для поля to 1
  83.     //static const char TO_2[]               PROGMEM;//раскомментируйте строку для добавления адреса для поля to 2
  84.  
  85.     static const char * const TO_SETTINGS[] PROGMEM;
  86.  
  87.     /*-----------------Темы-----------------*/
  88.     static const char SUBJECT_0[]        PROGMEM;
  89.     //static const char SUBJECT_1[]        PROGMEM;//раскомментируйте строку для добавления темы 1
  90.     //static const char SUBJECT_2[]        PROGMEM;//раскомментируйте строку для добавления темы 2
  91.     //static const char SUBJECT_3[]        PROGMEM;//раскомментируйте строку для добавления темы 3
  92.     //static const char SUBJECT_4[]        PROGMEM;//раскомментируйте строку для добавления темы 4
  93.  
  94.     static const char * const SUBJECT_LIST[] PROGMEM;
  95.  
  96.     /*-----------------Текст-----------------*/
  97.     static const char MESSAGE_0[]        PROGMEM;
  98.     //static const char MESSAGE_1[]        PROGMEM;//раскомментируйте строку для добавления сообщения 1
  99.     //static const char MESSAGE_2[]        PROGMEM;//раскомментируйте строку для добавления сообщения 2
  100.     //static const char MESSAGE_3[]        PROGMEM;//раскомментируйте строку для добавления сообщения 3
  101.     //static const char MESSAGE_4[]        PROGMEM;//раскомментируйте строку для добавления сообщения 4
  102.     //static const char MESSAGE_5[]        PROGMEM;//раскомментируйте строку для добавления сообщения 5
  103.     //static const char MESSAGE_6[]        PROGMEM;//раскомментируйте строку для добавления сообщения 6
  104.     //static const char MESSAGE_7[]        PROGMEM;//раскомментируйте строку для добавления сообщения 7
  105.     //static const char MESSAGE_8[]        PROGMEM;//раскомментируйте строку для добавления сообщения 8
  106.     //static const char MESSAGE_9[]        PROGMEM;//раскомментируйте строку для добавления сообщения 9
  107.  
  108.     static const char * const MESSAGE_LIST[] PROGMEM;
  109. /**------------------------------Настройки почты окончание--------------------------*/
  110.  
  111.  
  112.  
  113.     EthernetClient  _client;
  114.     char _responseCode[3];
  115.     bool _status;
  116.     bool readResponse ();
  117.     void closeConnection(uint8_t * p_processStatus, bool status);
  118.  
  119.     /*Команды передаваемые серверу сохранены в PROGMEM для экономии оперативной памяти*/
  120.     static const char COMMAND_EHLO[]        PROGMEM;
  121.     static const char COMMAND_AUTHLOGIN[]   PROGMEM;
  122.     static const char COMMAND_MAILFROM[]    PROGMEM;
  123.     static const char COMMAND_MAILTO[]      PROGMEM;
  124.     static const char COMMAND_DATA[]        PROGMEM;
  125.     static const char COMMAND_SUBJECT[]     PROGMEM;
  126.     static const char COMMAND_TO[]          PROGMEM;
  127.     static const char COMMAND_QUIT[]        PROGMEM;
  128. };
  129.  
  130. #endif

AdvancedMail.cpp

  1. #include "AdvancedMail.h"
  2. //#define NDBG //раскомментируйте строку если лог не нужен
  3.  
  4.  
  5. AdvancedSmtpClient::AdvancedSmtpClient(){}
  6.  
  7.     /**-----------------Настройки ящика-----------------*/
  8.  
  9.     /*-----------------SMTP серверы-------------------*/
  10.     const char AdvancedSmtpClient::SMTP_SERVER_0[] = "smtp.spaceweb.ru"; // замените на адрес вашего сервера
  11.     //const char SmtpClient::SMTP_SERVER_1[] = "укажите адрес SMTP сервера";//раскомментируйте строку для добавления SMTP сервера 1
  12.     //const char SmtpClient::SMTP_SERVER_2[] = "укажите адрес SMTP сервера";//раскомментируйте строку для добавления SMTP сервера 2
  13.  
  14.     const char * const AdvancedSmtpClient::SMTP_SERVER_SETTINGS[] = {
  15.         SMTP_SERVER_0
  16.         //,SMTP_SERVER_1 //раскомментируйте строку для добавления SMTP сервера 1
  17.         //,SMTP_SERVER_2//раскомментируйте строку для добавления SMTP сервера 2
  18.     } ;
  19.  
  20.     /*-----------------Порты-----------------*/
  21.     const char AdvancedSmtpClient::PORT_0[] = "25"; // замените на ваш порт
  22.     //const char SmtpClient::PORT_1[] = "укажите порт для сервера 1"; //раскомментируйте строку для добавления порта для сервера 1
  23.     //const char SmtpClient::PORT_2[] = "укажите порт для сервера 2"; //раскомментируйте строку для добавления порта для сервера 2
  24.  
  25.     const char * const AdvancedSmtpClient::PORT_SETTINGS[] = {
  26.         PORT_0
  27.         //,PORT_1   //раскомментируйте строку для добавления порта для сервера 1
  28.         //,PORT_2   //раскомментируйте строку для добавления порта для сервера 2
  29.     };
  30.  
  31.     /*-----------------Имена пользователей-----------------*/
  32.     const char AdvancedSmtpClient::USER_0[] = "c2VuZG1haWxAYXZyZ3VhcmQucnU="; // замените на ваш логин
  33.     //const char SmtpClient::USER_1[] = "укажите логин для сервера 1 в кодировке Base64";   //раскомментируйте строку для добавления логина для сервера 1
  34.     //const char SmtpClient::USER_2[] = "укажите логин для сервера 2 в кодировке Base64";   //раскомментируйте строку для добавления логина для сервера 2
  35.  
  36.     const char * const AdvancedSmtpClient::USER_SETTINGS[] = {
  37.         USER_0
  38.         //,USER_1  //раскомментируйте строку для добавления логина для сервера 1
  39.         //,USER_2  //раскомментируйте строку для добавления логина для сервера 2
  40.     };
  41.  
  42.     /*-----------------Пароли-----------------*/
  43.     const char AdvancedSmtpClient::PASS_0[] = "dDdONjI1NFk1Knk0V0NW";// замените на ваш пароль
  44.     //const char SmtpClient::PASS_1[] = "укажите пароль для сервера 1 в кодировке Base64";  //раскомментируйте строку для добавления пароля для сервера 1
  45.     //const char SmtpClient::PASS_2[] = "укажите пароль для сервера 1 в кодировке Base64";  //раскомментируйте строку для добавления пароля для сервера 2
  46.  
  47.     const char * const AdvancedSmtpClient::PASS_SETTINGS[] = {
  48.         PASS_0
  49.         //,PASS_1   //раскомментируйте строку для добавления пароля для сервера 1
  50.         //,PASS_2   //раскомментируйте строку для добавления пароля для сервера 1
  51.     };
  52.  
  53.     /*-----------------От кого письмо-----------------*/
  54.     const char AdvancedSmtpClient::FROM_0[] = "sendmail@avrguard.ru"; // замените на ваш адрес отправителя
  55.     //const char SmtpClient::FROM_1[] = "укажите адрес для поля from сервера 1";    //раскомментируйте строку для добавления адреса для поля from сервера 1
  56.     //const char SmtpClient::FROM_2[] = "укажите адрес для поля from сервера 2";    //раскомментируйте строку для добавления адреса для поля from сервера 2
  57.  
  58.     const char * const AdvancedSmtpClient::FROM_SETTINGS[] = {
  59.         FROM_0
  60.         //,FROM_1   //раскомментируйте строку для добавления адреса для поля from сервера 1
  61.         //,FROM_2   //раскомментируйте строку для добавления адреса для поля from сервера 2
  62.     };
  63.  
  64.     /*-----------------Кому письмо-----------------*/
  65.     const char AdvancedSmtpClient::TO_0[] = "test@test.com";//"!!!УКАЖИТЕ ЯЩИК ПОЛУЧАТЕЛЯ!!!";
  66.     //const char SmtpClient::TO_1[] = "укажите адрес для поля to"; //раскомментируйте строку для добавления адреса для поля to
  67.     //const char SmtpClient::TO_2[] = "укажите адрес для поля to"; //раскомментируйте строку для добавления адреса для поля to
  68.  
  69.     const char * const AdvancedSmtpClient::TO_SETTINGS[] = {
  70.         TO_0
  71.         //,TO_1   //раскомментируйте строку для добавления адреса для поля to
  72.         //,TO_2   //раскомментируйте строку для добавления адреса для поля to
  73.     };
  74.  
  75.     /*-----------------Темы-----------------*/
  76.     const char AdvancedSmtpClient::SUBJECT_0[] = "Test subject";
  77.     //const char SmtpClient::SUBJECT_1[] = "укажите тему 1";    //раскомментируйте строку для добавления темы 1
  78.     //const char SmtpClient::SUBJECT_2[] = "укажите тему 2";    //раскомментируйте строку для добавления темы 2
  79.     //const char SmtpClient::SUBJECT_3[] = "укажите тему 3";    //раскомментируйте строку для добавления темы 3
  80.     //const char SmtpClient::SUBJECT_4[] = "укажите тему 4";    //раскомментируйте строку для добавления темы 4
  81.  
  82.  
  83.     const char * const AdvancedSmtpClient::SUBJECT_LIST[] = {
  84.         SUBJECT_0
  85.         //,SUBJECT_1    //раскомментируйте строку для добавления темы 1
  86.         //,SUBJECT_2    //раскомментируйте строку для добавления темы 2
  87.         //,SUBJECT_3    //раскомментируйте строку для добавления темы 3
  88.         //,SUBJECT_4    //раскомментируйте строку для добавления темы 4
  89.     };
  90.  
  91.     /*-----------------Текст-----------------*/
  92.     const char AdvancedSmtpClient::MESSAGE_0[] = "Test message";
  93.     //const char SmtpClient::MESSAGE_1[] = "укажите сообщение 1";   //раскомментируйте строку для добавления сообщения 1
  94.     //const char SmtpClient::MESSAGE_2[] = "укажите сообщение 2";   //раскомментируйте строку для добавления сообщения 2
  95.     //const char SmtpClient::MESSAGE_3[] = "укажите сообщение 3";   //раскомментируйте строку для добавления сообщения 3
  96.     //const char SmtpClient::MESSAGE_4[] = "укажите сообщение 4";   //раскомментируйте строку для добавления сообщения 4
  97.     //const char SmtpClient::MESSAGE_5[] = "укажите сообщение 5";   //раскомментируйте строку для добавления сообщения 5
  98.     //const char SmtpClient::MESSAGE_6[] = "укажите сообщение 6";   //раскомментируйте строку для добавления сообщения 6
  99.     //const char SmtpClient::MESSAGE_7[] = "укажите сообщение 7";   //раскомментируйте строку для добавления сообщения 7
  100.     //const char SmtpClient::MESSAGE_8[] = "укажите сообщение 8";   //раскомментируйте строку для добавления сообщения 8
  101.     //const char SmtpClient::MESSAGE_9[] = "укажите сообщение 9";   //раскомментируйте строку для добавления сообщения 9
  102.  
  103.     const char * const AdvancedSmtpClient::MESSAGE_LIST[] = {
  104.         MESSAGE_0
  105.         //,MESSAGE_1    //раскомментируйте строку для добавления сообщения 1
  106.         //,MESSAGE_2    //раскомментируйте строку для добавления сообщения 2
  107.         //,MESSAGE_3    //раскомментируйте строку для добавления сообщения 3
  108.         //,MESSAGE_4    //раскомментируйте строку для добавления сообщения 4
  109.         //,MESSAGE_5    //раскомментируйте строку для добавления сообщения 5
  110.         //,MESSAGE_6    //раскомментируйте строку для добавления сообщения 6
  111.         //,MESSAGE_7    //раскомментируйте строку для добавления сообщения 7
  112.         //,MESSAGE_8    //раскомментируйте строку для добавления сообщения 8
  113.         //,MESSAGE_9    //раскомментируйте строку для добавления сообщения 9
  114.     };
  115.  
  116. bool AdvancedSmtpClient::sendMail(uint8_t boxNum, uint8_t recipientNum, uint8_t subjectNum, uint8_t messageNum){
  117.     static uint8_t processStatus = 0;
  118.     static char buff[50]; // если есть любая строка (сервер, логин, пароль, адреса, тема или сообщение) более указанной длины (50) увеличить размер буфера до нужной длины.
  119.     if (!_client.connected()){
  120.         char portBuff[4];
  121.         strcpy_P(buff, pgm_read_word_near((int)(SMTP_SERVER_SETTINGS + boxNum)));
  122.         strcpy_P(portBuff, pgm_read_word_near((int)(PORT_SETTINGS + boxNum)));
  123.         if (_client.connect(buff, atoi(portBuff))){
  124.             #ifndef NDBG
  125.             Serial.println(F("SimpleMail >> SMTP client connected"));
  126.             #endif // NDBG
  127.         }
  128.         else {
  129.             #ifndef NDBG
  130.             Serial.println(F("SimpleMail >> SMTP client connection failed"));
  131.             #endif // NDBG
  132.         }
  133.     }
  134.     else {
  135.         switch (processStatus){
  136.             case 0:
  137.                 if (readResponse ()){
  138.                     if(atoi(_responseCode) == 220 || atoi(_responseCode) == 221){
  139.                         _client.println(strcpy_P(buff, COMMAND_EHLO));
  140.                         processStatus = 1;
  141.                     }
  142.                     else{
  143.                         closeConnection(&processStatus, false);
  144.                         return true;
  145.                     }
  146.                 }
  147.             break;
  148.             case 1:
  149.                 if (readResponse ()){
  150.                     if(atoi(_responseCode) == 250){
  151.                         _client.println(strcpy_P(buff, COMMAND_AUTHLOGIN));
  152.                         processStatus = 2;
  153.  
  154.                     }
  155.                     else{
  156.                         closeConnection(&processStatus, false);
  157.                         return true;
  158.                     }
  159.                 }
  160.             break;
  161.             case 2:
  162.                 if (readResponse ()){
  163.                     if(atoi(_responseCode) == 334){
  164.                         _client.println(strcpy_P(buff, pgm_read_word_near((int)(USER_SETTINGS + boxNum))));
  165.                         processStatus = 3;
  166.                     }
  167.                     else{
  168.                         /*closeConnection(&processStatus, false);
  169.                         return true;*/
  170.                     }
  171.                 }
  172.             case 3:
  173.                 if (readResponse ()){
  174.                     if(atoi(_responseCode) == 334){
  175.                         _client.println(strcpy_P(buff, pgm_read_word_near((int)(PASS_SETTINGS + boxNum))));
  176.                         processStatus = 4;
  177.                     }
  178.                     else{
  179.                         closeConnection(&processStatus, false);
  180.                         return true;
  181.                     }
  182.  
  183.                 }
  184.             break;
  185.             case 4:
  186.                 if (readResponse ()){
  187.                     if(atoi(_responseCode) == 235){
  188.                         strcpy_P(buff, COMMAND_MAILFROM);
  189.                         _client.print(buff);
  190.                         _client.println(strcpy_P(buff, pgm_read_word_near((int)(FROM_SETTINGS + boxNum))));
  191.                         processStatus = 5;
  192.                     }
  193.                     else{
  194.                         closeConnection(&processStatus, false);
  195.                         return true;
  196.                     }
  197.                 }
  198.             break;
  199.             case 5:
  200.                 if (readResponse ()){
  201.                     if(atoi(_responseCode) == 250){
  202.                         strcpy_P(buff, COMMAND_MAILTO);
  203.                         _client.print(buff);
  204.                         _client.println(strcpy_P(buff, pgm_read_word_near((int)(TO_SETTINGS + recipientNum))));
  205.                         processStatus = 6;
  206.                     }
  207.                     else{
  208.                         closeConnection(&processStatus, false);
  209.                         return true;
  210.                     }
  211.                 }
  212.             break;
  213.             case 6:
  214.                 if (readResponse ()){
  215.                     if(atoi(_responseCode) == 250){
  216.                         strcpy_P(buff, COMMAND_DATA);
  217.                         _client.println(buff);
  218.                         processStatus = 7;
  219.                     }
  220.                     else{
  221.                         closeConnection(&processStatus, false);
  222.                         return true;
  223.                     }
  224.                 }
  225.             break;
  226.             case 7:
  227.                 if (readResponse ()){
  228.                     if(atoi(_responseCode) == 354){
  229.                         strcpy_P(buff, COMMAND_TO);
  230.                         _client.print(buff);
  231.                         _client.println(strcpy_P(buff, pgm_read_word_near((int)(TO_SETTINGS + recipientNum))));
  232.                         strcpy_P(buff, COMMAND_SUBJECT);
  233.                         _client.print(buff);
  234.                         _client.println(strcpy_P(buff, pgm_read_word_near((int)(SUBJECT_LIST + subjectNum))));
  235.                         _client.println();
  236.                         _client.println(strcpy_P(buff, pgm_read_word_near((int)(MESSAGE_LIST + messageNum))));
  237.                         _client.println(F("."));
  238.                         processStatus = 8;
  239.                     }
  240.                     else{
  241.                         closeConnection(&processStatus, false);
  242.                         return true;
  243.                     }
  244.                 }
  245.             break;
  246.             case 8:
  247.                 if (readResponse ()){
  248.                     if(atoi(_responseCode) == 250){
  249.                         strcpy_P(buff, COMMAND_QUIT);
  250.                         _client.println(buff);
  251.                         processStatus = 9;
  252.  
  253.                     }
  254.                     else{
  255.                         closeConnection(&processStatus, false);
  256.                         return true;
  257.                     }
  258.                 }
  259.             break;
  260.             case 9:
  261.                 if (readResponse ()){
  262.                     if(atoi(_responseCode) == 221){
  263.                         closeConnection(&processStatus, true);
  264.                         return true;
  265.                     }
  266.                 }
  267.             break;
  268.             default:
  269.                 Serial.println(F("Zombies rising!"));
  270.         }
  271.     }
  272.     return false;
  273. };
  274. bool AdvancedSmtpClient::readResponse (){
  275.     if (_client.available()) {
  276.         static uint8_t n = 0;
  277.         #ifndef NDBG
  278.         if (!n) Serial.print(F("SMTP SERVER >>"));
  279.         #endif // NDBG
  280.         if (n < 3){
  281.             char sym = _client.read();
  282.             _responseCode[n] = sym;
  283.             #ifndef NDBG
  284.             Serial.print(sym);
  285.             #endif // NDBG
  286.             n++;
  287.             return false;
  288.         }
  289.         else {
  290.             char sym = _client.read();
  291.             #ifndef NDBG
  292.             Serial.print(sym);
  293.             #endif // NDBG
  294.             if (sym == 0x0A){
  295.                 n = 0;
  296.                 return true;
  297.             }
  298.             return false;
  299.         }
  300.     }
  301.     else {
  302.         return false;
  303.     }
  304. };
  305. void AdvancedSmtpClient::closeConnection(uint8_t * p_processStatus, bool status){
  306.     * p_processStatus = 0;
  307.     _client.flush();
  308.     _client.stop();
  309.     #ifndef NDBG
  310.     if(!_client.connected()) {
  311.         Serial.println();
  312.         if (status) Serial.println(F("SimpleMail >> NO error detected"));
  313.         else Serial.println(F("SimpleMail >> Error detected"));
  314.         Serial.println(F("SimpleMail >> SMTP client disconnected"));
  315.     }
  316.     #endif // NDBG
  317.     _status = status;
  318. };
  319. bool AdvancedSmtpClient::getStatus(){return _status;};
  320.  
  321. /**-----------------Команды серверу-----------------*/
  322. const char AdvancedSmtpClient::COMMAND_EHLO[] = "EHLO 127.0.0.1";
  323. const char AdvancedSmtpClient::COMMAND_AUTHLOGIN[] = "AUTH LOGIN";
  324. const char AdvancedSmtpClient::COMMAND_MAILFROM[] = "MAIL From:";
  325. const char AdvancedSmtpClient::COMMAND_MAILTO[] = "RCPT To:";
  326. const char AdvancedSmtpClient::COMMAND_DATA[] = "DATA";
  327. const char AdvancedSmtpClient::COMMAND_SUBJECT[] = "Subject:";
  328. const char AdvancedSmtpClient::COMMAND_TO[] = "To:";
  329. const char AdvancedSmtpClient::COMMAND_QUIT[] = "QUIT";

Пример использования

  1. #include <SPI.h> // подключаем библиотеку SPI
  2. #include <Ethernet.h> // подключаем библиотеку Ethernet
  3. #include <AdvancedMail.h> // подключаем библиотеку AdvancedMail
  4.  
  5. uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // задаем MAKадрес
  6. IPAddress ip(192, 168, 0, 77); // задаем айпи адрес (проверьте чтобы была корректная подсеть и не было конфликта айпи адресов)
  7. AdvancedSmtpClient client; // создаем экземпляр класса AdvancedSmtpClient (клиента SMTP)
  8.  
  9. bool flag = false; // создаем флаг для отправки письма
  10.  
  11. void setup() {
  12.   Serial.begin(9600); // инициализируем Serial
  13.   Ethernet.begin(mac, ip); // инициализируем Ethernet соединение
  14.   delay(1000);
  15. }
  16.  
  17. void loop() {
  18.   test();
  19.    if (flag) {// если флаг есть - пытаемся отправить письмо
  20.     if (client.sendMail(0,0,0,0)){// если сеанс закончен
  21.       flag = false;//сбрасываем флаг
  22.       if (client.getStatus()) Serial.println(F("Message sent!"));
  23.       else Serial.println(F("Message not sent!"));
  24.     }
  25.   }
  26.  
  27. }
  28. void test() {// при приеме из Serial знака 0 переводит flag в true для инициализации отправки письма
  29.   if (Serial.available()) {
  30.     byte symbol = Serial.read();
  31.     if (symbol == '0') {
  32.       Serial.println(F("Try to send message..."));
  33.       flag = true;
  34.     }
  35.   }
  36. }


Оцените пожалуйста статью:

ПечальноТак себеНе плохоХорошоОтличная статья! 3 оценок.
Загрузка...

13 Replies to “Отправка почты с помощью ARDUINO.

  1. Александр! День добрый! В примере к библиотеке “SimpleMail” в строчке 25 ошибка при компиляции “‘test’ was not declared in this scope”. Если эту строчку заблокировать то код программы загружается но не работоспособен.

  2. День добрый! в примере к библиотеке “SimpleMail” строчка №25 при компиляции выдаёт ошибку “не известная переменная”. Как убрать эту ошибку? Заранее спасибо!

    1. Евгений! В строке 25 мы вызываем ФУНКЦИЮ test() ! Там нет переменной. Реализация этой функции описана ниже loop(). У меня все компилируется.
      Вот лог:
      Используем библиотеку SPI версии 1.0 из папки: F:\arduino\DATAArduino\hardware\arduino\avr\libraries\SPI
      Используем библиотеку Ethernet версии 1.1.2 из папки: F:\arduino\DATAArduino\libraries\Ethernet
      Используем библиотеку SimpleMail в папке: F:\arduino\DATAArduino\libraries\SimpleMail (legacy)
      Скетч использует 11288 байт (34%) памяти устройства. Всего доступно 32256 байт.
      Глобальные переменные используют 888 байт (43%) динамической памяти, оставляя 1160 байт для локальных переменных. Максимум: 2048 байт.

      Присылайте лог. Будем посмотреть

  3. Александр! Заполнил поля (приложено внизу). После отправления 0 в порт пишет:

    Try to send mail…
    SimpleMail >> SMTP client connection failed
    SimpleMail >> SMTP client connected

    и все. Сообщение не отправлено. В чем может быть проблема?

    #include // подключаем библиотеку SPI
    #include // подключаем библиотеку Ethernet
    #include // подключаем библиотеку SimpleMail

    uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };// задаем MAKадрес
    IPAddress ip(192, 168, 1, 16);// задаем айпи адрес (проверьте чтобы была корректная подсеть и не было конфликта айпи адресов)
    SimpleSmtpClient client; //создаем экземпляр класса SimpleSmtpClient (клиента SMTP)

    char smtpServer[] = “smtp.mail.ru”; // указываем адрес сервера
    uint16_t port = 465; // указываем порт сервера
    char user[] = “ard****erf@mail.ru”; // указываем логин
    char pass[] = “Zxc*****Rty$56”; // указываем пароль
    char mailto[] = “daf****y@mail.ru”; // указываем адрес получателя
    char mailfrom[] = “ard****erf@mail.ru”; // указываем адрес отправителя
    char subject[] = “Test subject”; // указываем тему
    char message[] = “Test\nmessage”; // указываем текст сообщения
    bool flag = false;// создаем флаг для отправки письма
    void setup() {
    Serial.begin(9600);// инициализируем Serial
    Ethernet.begin(mac, ip);// инициализируем Ethernet соединение
    delay(1000);
    }
    void loop() {
    // put your main code here, to run repeatedly:
    test();
    if (flag) {// если флаг есть – пытаемся отправить письмо
    if (client.sendMail(smtpServer,port,user,pass,mailfrom,mailto,subject,message)) {// если сеанс закончен
    flag = false;//сбрасываем флаг
    if (client.getStatus()) Serial.println(F(“Message sent!”));
    else Serial.println(F(“Message not sent!”));
    }
    }
    }
    void test() {
    if (Serial.available()) {// при приеме из Serial знака 0 переводит flag в true для инициализации отправки письма
    byte symbol = Serial.read();
    if (symbol == ‘0’) {
    Serial.println(F(“Try to send mail…”));
    flag = true;
    }
    }
    }

    1. Даниил здравствуйте.
      Вы пытаетесь установить соединение с сервером по 465 порту, который использует шифрование (SSL/TLS)

      uint16_t port = 465; // указываем порт сервера

      Данная библиотека не поддерживает режим работы с шифрованием, т.к. у ардуинки мало памяти. Вам нужно найти почтовый сервис или хостинг с почтой, с возможностью работы с открытым SMTP (например по порту 25).

      1. Есть ли какой-то способ переделать, с поддержкой шифрования, очень хотелось бы использовать именно mail.ru

      2. И еще вопрос, если нельзя переработать, то какой почтовый сервис выбрать

      3. В течении 2 часов искал другую почту. Вот что вышло:

        Try to send mail…
        SimpleMail >> SMTP client connected
        SMTP SERVER >>220 smtp.ngs.ru ESMTP ready
        SMTP SERVER >>250-smtp.ngs.ru
        SMTP SERVER >>250-SIZE 50000000
        SMTP SERVER >>250-ETRN
        SMTP SERVER >>250-ENHANCEDSTATUSCODES

        SimpleMail >> Error detected
        SimpleMail >> SMTP client disconnected
        Message not sent!

        В чем может быть ошибка?

      4. Еще чуток покопался и получил такой результат: (опять вернулся на mail.ru)

        Try to send mail…
        SimpleMail >> SMTP client connected
        SMTP SERVER >>220 smtp3.mail.ru ESMTP ready (Looking for Mail for your domain? Visit https://biz.mail.ru)
        SMTP SERVER >>250-smtp3.mail.ru
        SMTP SERVER >>250-SIZE 73400320
        SMTP SERVER >>250-8BITMIME
        SMTP SERVER >>250-PIPELINING
        SMTP SERVER >>250 STARTTLS
        SMTP SERVER >>500 AUTH available only with SSL or TLS

        SimpleMail >> Error detected
        SimpleMail >> SMTP client disconnected
        Message not sent!

        1. Даниил! Вы опять соединяетесь с сервером с ШИФРОВАНИЕМ!

          SMTP SERVER >>250 STARTTLS
          SMTP SERVER >>500 AUTH available only with SSL or TLS

          К сожалению, нет возможности реализовать шифрование на простой ардуинке. Нужно использовать другую плату, либо одеть на плату Dragino Yun shield и действовать через OpenVPN, например использовать программу xmail или что-то подобное.

          1. Я не могу понять что я не так делаю. Мне нужно использовать другой адрес сервера или вообще другую почту или что-то другое. Не могли бы вы предоставить пример, где нужно будет заменить лишь email и пароль, а то я не сильно много в этом понимаю если честно…

          2. Даниил, нужно найти | купить | организовать хостинг где есть поддержка почтового сервера БЕЗ шифрования. Найти очень сложно, т.к. все гиганты почты уже давно используют шифрование. Если данная услуга нужна вам для множества проектов или для себя – проще купить. Я писал в посте что данная услуга обходится приблизительно в 600 р/год.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *