• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Делюсь опытом Если при отправке e-mail через WiFiClientSecure часто наступает wdt.reset...

Paul_B

Member
В файле WiFiClientSecure.cpp необходимо произвести изменения:
1. _timeout = 5000 (вместо 15000) в двух местах (может это и не надо, а установить client.setTimeout(5000), но у меня это не приносило плоды, возможно из-за ошибки, изложенной в п.2)
2. заменить функцию
Код:
int WiFiClientSecure::connect(const char* name, uint16_t port)
{
    IPAddress remote_addr;
    if (!WiFi.hostByName(name, remote_addr, _timeout)) {
        return 0;
    }
    if (!WiFiClient::connect(remote_addr, port)) {
        return 0;
    }
    return _connectSSL(name);
}
Там, в отличие от WiFiclient.cpp стояло if (!WiFi.hostByName(name, remote_addr)) поэтому часто были зависания тут и перезагрузка по wdt.reset
3. В файлах WiFiclient.cpp и WiFiClientSecure.cpp заменить yield() на delay(1);

Полностью модифицированный файл прилагаю.
Заменяется по пути C:\DOCUMENTS AND SETTINGS\USER\APPDATA\LOCAL\ARDUINO15\PACKAGES\ESP8266\HARDWARE\ESP8266\2.4.2\LIBRARIES\ESP8266WIFI\SRC\WiFiClientSecure.cpp

Сами функции, реализующие отправку e-mail вот:
Код:
#include <WiFiClientSecure.h>
#include <base64.h>

//#define NDEBUG

uint16_t smtpPort = 465;
char* Mail_Message=NULL;
char* Mail_Subj=NULL;
char* smtpUser=NULL;
char* smtpHost=NULL;
char* smtpPass=NULL;
char* mailTo=NULL;


static inline bool checkResponse(const String& response, int16_t code) {
  return response.startsWith(String(code) + ' ');
}

static bool checkResponse(const String& response, int16_t code, const String& errorMsg) {
  bool result = checkResponse(response, code);

  if (! result) {
    Serial.print(errorMsg);
    Serial.print(F(": \""));
    if (response.endsWith(F("\r\n")))
      Serial.print(response.substring(0, response.length() - 2));
    else
      Serial.print(response);
    Serial.println(F("\"!"));
  }

  return result;
}

static String getLine(WiFiClient& client) {
  String result;

  if (client.connected())
    result = client.readStringUntil('\n');
//#ifndef NDEBUG
//  Serial.print(F("<<"));
//  Serial.println(result);
//#endif

  return result;
}

static void sendLine(WiFiClient& client, const String& str) {
//#ifndef NDEBUG
//  Serial.print(F(">>"));
//  Serial.println(str);
//#endif
  if (client.connected())
    client.println(str);
}

static String sendCommand(WiFiClient& client, const String& str) {
  sendLine(client, str);
  client.flush();

  return getLine(client);
}               

bool sendMail(char* smtpHost, uint16_t smtpPort, char* smtpUser, char* smtpPassword, char* mailTo, char* mailSubject, const String& mailMessage) {
  WiFiClientSecure client;
  String str;

// client.setTimeout(2000); // 15 sec. read timeout

  Serial.print(F("Connecting to "));
  Serial.println(smtpHost);
  yield();
  if (! client.connect(smtpHost, smtpPort)) {
    Serial.println(F("Connection failed!"));
    return false;
  }
  Serial.println(F("Connected OK..."));

  str = getLine(client);
  if (! checkResponse(str, 220, F("SMTP connection error")))
    return false;
  str = sendCommand(client, F("HELO esp8266.local"));
  if (! checkResponse(str, 250, F("SMTP HELO error")))
    return false;
  if (String(smtpPassword).length()) {
    str = sendCommand(client, F("AUTH LOGIN"));
    if (! checkResponse(str, 334, F("SMTP AUTH error")))
      return false;
    str = sendCommand(client, base64::encode(smtpUser));
    if (! checkResponse(str, 334, F("SMTP AUTH USER error")))
      return false;
    str = sendCommand(client, base64::encode(smtpPassword));
    if (! checkResponse(str, 235, F("SMTP AUTH PASS error")))
      return false;
  }
  str = F("MAIL FROM: <");
  str += smtpUser;
  str += '>';
  str = sendCommand(client, str);
  if (! checkResponse(str, 250, F("SMTP MAIL FROM error")))
    return false;
  str = F("RCPT TO: <");
  str += mailTo;
  str += '>';
  str = sendCommand(client, str);
  if (! checkResponse(str, 250, F("SMTP RCPT TO error")))
    return false;
  str = sendCommand(client, F("DATA"));
  if (! checkResponse(str, 354, F("SMTP DATA error")))
    return false;
  str = F("Subject: =?utf-8?B?");
  str += base64::encode(mailSubject);
  str += F("=?=");
  sendLine(client, str);
  sendLine(client, F("MIME-Version: 1.0"));
  sendLine(client, F("Content-type: text/plain; charset=utf-8"));
  str = F("From: <");
  str += smtpUser;
  str += '>';
  sendLine(client, str);
  str = F("To: <");
  str += mailTo;
  str += '>';
  sendLine(client, str);
  sendLine(client, "");
  sendLine(client, mailMessage);
  str = sendCommand(client, F("\r\n."));
  if (! checkResponse(str, 250, F("SMTP send error")))
    return false;
  sendCommand(client, F("QUIT"));
  Serial.println(F("Connect END..."));

  client.stop();

  return true;
}
вызов: sendMail(smtpHost, smtpPort, smtpUser, smtpPass, mailTo, Mail_Subj, Mail_Message)
Например:
Код:
String smtpHost = "smtp.mail.ru";
uint16_t smtpPort = 465;
String smtpUser = "12345@mail.ru";
String smtpPass = "12345pass";
String mailTo = "54321@yandex.ru";
Это проще вставить в проект, чем подключать библиотеки.

Работает на mail.ru yandex.ru и gmail.com
 

Вложения

Последнее редактирование:

Paul_B

Member
Если раньше при отправке ~50 обязательно происходила перезагрузка на этапе коннектинга к хосту, то сейчас уже работает 3 часа, отправлено более 150 сообщений и все ОК.
 

Алексей.

Active member
При DNS атаке, атакуемому на запрос разрешении доменного имени приходит ip адрес атакующего, атакуемый устанавливает, как он считает, защищенное соединение с хостом, получает цепочку сертификатов заканчивающуюся корневым сертификатом.
Атакующий присылает свой самодельный корневой сертификат.
Используя WiFiClientSecure можно проверить заранее известный fingerprint или установить доверенный CA и не доверять сертификату полученному от атакующего.
Драматизм ситуации в том, что корневые сертификаты иногда тухнут. Вопрос как обеспечить на есп обновление корневых сертификатов или fingerprint-ов.
 
Сверху Снизу