ESP32-CAM: отправка фото по электронной почте (SMTP-сервер)

В этом руководстве показано, как отправить снятые фотографии с ESP32-CAM на вашу электронную почту с помощью SMTP-сервера. Мы покажем простой пример, который делает фото при загрузке ESP32 и отправляет его в виде вложения в письме. Последняя сделанная фотография временно сохраняется в файловой системе ESP32 LittleFS.

ESP32-CAM отправка фото по Email через SMTP-сервер Arduino IDE

Обновлено 19 сентября 2023.

Чтобы этот проект работал, ESP32-CAM должен быть подключён к маршрутизатору с доступом в интернет – то есть подключён к вашей локальной сети.

Этот проект совместим с любой платой ESP32 с камерой OV2640. Вам просто нужно убедиться, что вы используете правильное назначение пинов для вашей платы: ESP32-CAM Camera Boards: назначение пинов и GPIO.

Библиотека ESP Mail Client

Для отправки писем с ESP32-CAM мы будем использовать библиотеку ESP-Mail-Client. Эта библиотека позволяет ESP32 отправлять и получать письма с вложениями или без них через SMTP и IMAP серверы.

В этом проекте мы будем использовать SMTP для отправки письма с вложением. Вложением будет фото, сделанное с ESP32-CAM.

SMTP означает Simple Mail Transfer Protocol (простой протокол передачи почты) и является интернет-стандартом для передачи электронной почты. Для отправки писем через код вам нужно знать настройки вашего SMTP-сервера. У каждого почтового провайдера свой SMTP-сервер.

Установка библиотеки ESP-Mail-Client

Перед продолжением этого руководства вам необходимо установить библиотеку ESP-Mail-Client.

Перейдите в Sketch > Include Library > Manage Libraries и найдите ESP Mail Client. Установите библиотеку ESP Mail Client от Mobizt.

Установка библиотеки ESP Mail Client в Arduino IDE

Email отправителя (новый аккаунт)

Мы рекомендуем создать новый email-аккаунт для отправки писем на ваш основной личный адрес. Не используйте вашу основную личную почту для отправки писем через ESP32. Если что-то пойдёт не так в вашем коде или если по ошибке вы сделаете слишком много запросов, вас могут заблокировать или временно отключить ваш аккаунт.

Мы будем использовать новый аккаунт Gmail.com для отправки писем, но вы можете использовать любого другого почтового провайдера. Email получателя может быть вашей личной почтой без каких-либо проблем.

Создание аккаунта отправителя

Создайте новый email-аккаунт для отправки писем с ESP32. Если вы хотите использовать аккаунт Gmail, перейдите по этой ссылке для создания нового.

Gmail Создание нового аккаунта

Создание пароля приложения

Вам нужно создать пароль приложения, чтобы ESP32 мог отправлять письма с использованием вашего аккаунта Gmail. Пароль приложения – это 16-значный код, который даёт менее защищённому приложению или устройству разрешение на доступ к вашему аккаунту Google. Узнайте больше о входе с паролями приложений здесь.

Пароль приложения можно использовать только с аккаунтами, у которых включена двухэтапная аутентификация (`2-Step Verification <https://support.google.com/accounts/answer/185839>`_).

  1. Откройте ваш аккаунт Google.

  2. На панели навигации выберите Безопасность.

  3. В разделе «Вход в Google» выберите Двухэтапная аутентификация > Начать.

  4. Следуйте инструкциям на экране.

После включения двухэтапной аутентификации вы можете создать пароль приложения.

  1. Откройте ваш аккаунт Google.

  2. В панели поиска найдите App Passwords.

  3. Откройте меню App Passwords.

Аккаунт Google создание пароля приложения для отправки email с ESP32
  1. Дайте имя паролю приложения, например ESP. Затем нажмите Create. Появится окно с паролем, который вы будете использовать с ESP32 или ESP8266 для отправки писем. Сохраните этот пароль (даже если написано, что вам не нужно его запоминать), потому что он понадобится позже.

Создание пароля приложения для использования с ESP

Появится окно с паролем, который вы будете использовать с ESP32 для отправки писем. Сохраните этот пароль (даже если написано, что вам не нужно его запоминать), потому что он понадобится позже.

Сгенерированный пароль приложения аккаунта Google

Теперь у вас должен быть пароль приложения, который вы будете использовать в коде ESP32 для отправки писем.

Пароль приложения Gmail создан для ESP32 отправки email

Если вы используете другого почтового провайдера, проверьте, как создать пароль приложения. Вы должны найти инструкции с помощью быстрого поиска в Google «ваш_почтовый_провайдер + create app password».

Настройки SMTP-сервера Gmail

Если вы используете аккаунт Gmail, вот настройки SMTP-сервера:

  • SMTP-сервер: smtp.gmail.com

  • SMTP имя пользователя: Полный адрес Gmail

  • SMTP пароль: Ваш пароль Gmail

  • SMTP порт (TLS): 587

  • SMTP порт (SSL): 465

  • SMTP TLS/SSL обязательно: да

Настройки SMTP-сервера Outlook

Для аккаунтов Outlook настройки SMTP-сервера следующие:

  • SMTP-сервер: smtp.office365.com

  • SMTP имя пользователя: Полный адрес Outlook

  • SMTP пароль: Ваш пароль Outlook

  • SMTP порт: 587

  • SMTP TLS/SSL обязательно: Да

Настройки SMTP-сервера Live или Hotmail

Для аккаунтов Live или Hotmail настройки SMTP-сервера следующие:

  • SMTP-сервер: smtp.live.com

  • SMTP имя пользователя: Полный адрес Live/Hotmail

  • SMTP пароль: Ваш пароль Windows Live Hotmail

  • SMTP порт: 587

  • SMTP TLS/SSL обязательно: Да

Если вы используете другого почтового провайдера, вам нужно найти настройки его SMTP-сервера. Теперь у вас есть всё необходимое для начала отправки писем с ESP32-CAM.

Код – ESP32-CAM отправка Email

Следующий код делает фото при первой загрузке ESP32-CAM и отправляет его на ваш email-аккаунт. Перед загрузкой кода убедитесь, что вы вставили настройки вашего email отправителя, а также email получателя.

/*********
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete instructions at https://RandomNerdTutorials.com/esp32-cam-projects-ebook/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/

#include "esp_camera.h"
#include "SPI.h"
#include "driver/rtc_io.h"
#include "soc/rtc_cntl_reg.h"  // Disable brownout problems
#include <ESP_Mail_Client.h>
#include <FS.h>
#include <WiFi.h>

// REPLACE WITH YOUR NETWORK CREDENTIALS
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// To send Email using Gmail use port 465 (SSL) and SMTP Server smtp.gmail.com
// You need to create an email app password
#define emailSenderAccount    "SENDER_EMAIL@gmail.com"
#define emailSenderPassword   "YOUR_EMAIL_APP_PASSWORD"
#define smtpServer            "smtp.gmail.com"
#define smtpServerPort        465
#define emailSubject          "ESP32-CAM Photo Captured"
#define emailRecipient        "YOUR_EMAIL_RECIPIENT@example.com"

#define CAMERA_MODEL_AI_THINKER

#if defined(CAMERA_MODEL_AI_THINKER)
  #define PWDN_GPIO_NUM     32
  #define RESET_GPIO_NUM    -1
  #define XCLK_GPIO_NUM      0
  #define SIOD_GPIO_NUM     26
  #define SIOC_GPIO_NUM     27
  #define Y9_GPIO_NUM       35
  #define Y8_GPIO_NUM       34
  #define Y7_GPIO_NUM       39
  #define Y6_GPIO_NUM       36
  #define Y5_GPIO_NUM       21
  #define Y4_GPIO_NUM       19
  #define Y3_GPIO_NUM       18
  #define Y2_GPIO_NUM        5
  #define VSYNC_GPIO_NUM    25
  #define HREF_GPIO_NUM     23
  #define PCLK_GPIO_NUM     22
#else
  #error "Camera model not selected"
#endif

/* The SMTP Session object used for Email sending */
SMTPSession smtp;

/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status);

// Photo File Name to save in LittleFS
#define FILE_PHOTO "photo.jpg"
#define FILE_PHOTO_PATH "/photo.jpg"

void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector

  Serial.begin(115200);
  Serial.println();

  // Connect to Wi-Fi
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi...");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  // Print ESP32 Local IP Address
  Serial.print("IP Address: http://");
  Serial.println(WiFi.localIP());

  // Init filesystem
  ESP_MAIL_DEFAULT_FLASH_FS.begin();

  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sccb_sda = SIOD_GPIO_NUM;
  config.pin_sccb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  config.grab_mode = CAMERA_GRAB_LATEST;

  if(psramFound()){
    config.frame_size = FRAMESIZE_UXGA;
    config.jpeg_quality = 10;
    config.fb_count = 1;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }

  // Initialize camera
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }

  capturePhotoSaveLittleFS();
  sendPhoto();
}

void loop() {

}

// Capture Photo and Save it to LittleFS
void capturePhotoSaveLittleFS( void ) {
  // Dispose first pictures because of bad quality
  camera_fb_t* fb = NULL;
  // Skip first 3 frames (increase/decrease number as needed).
  for (int i = 0; i < 3; i++) {
    fb = esp_camera_fb_get();
    esp_camera_fb_return(fb);
    fb = NULL;
  }

  // Take a new photo
  fb = NULL;
  fb = esp_camera_fb_get();
  if(!fb) {
    Serial.println("Camera capture failed");
    delay(1000);
    ESP.restart();
  }

  // Photo file name
  Serial.printf("Picture file name: %s\n", FILE_PHOTO_PATH);
  File file = LittleFS.open(FILE_PHOTO_PATH, FILE_WRITE);

  // Insert the data in the photo file
  if (!file) {
    Serial.println("Failed to open file in writing mode");
  }
  else {
    file.write(fb->buf, fb->len); // payload (image), payload length
    Serial.print("The picture has been saved in ");
    Serial.print(FILE_PHOTO_PATH);
    Serial.print(" - Size: ");
    Serial.print(fb->len);
    Serial.println(" bytes");
  }
  // Close the file
  file.close();
  esp_camera_fb_return(fb);
}

void sendPhoto( void ) {

  /** Enable the debug via Serial port
   * none debug or 0
   * basic debug or 1
  */
  smtp.debug(1);

  /* Set the callback function to get the sending results */
  smtp.callback(smtpCallback);

  /* Declare the session config data */
  Session_Config config;

  /*Set the NTP config time
  For times east of the Prime Meridian use 0-12
  For times west of the Prime Meridian add 12 to the offset.
  Ex. American/Denver GMT would be -6. 6 + 12 = 18
  See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets
  */
  config.time.ntp_server = F("pool.ntp.org,time.nist.gov");
  config.time.gmt_offset = 0;
  config.time.day_light_offset = 1;

  /* Set the session config */
  config.server.host_name = smtpServer;
  config.server.port = smtpServerPort;
  config.login.email = emailSenderAccount;
  config.login.password = emailSenderPassword;
  config.login.user_domain = "";

  /* Declare the message class */
  SMTP_Message message;

  /* Enable the chunked data transfer with pipelining for large message if server supported */
  message.enable.chunking = true;

  /* Set the message headers */
  message.sender.name = "ESP32-CAM";
  message.sender.email = emailSenderAccount;

  message.subject = emailSubject;
  message.addRecipient("Sara", emailRecipient);

  String htmlMsg = "<h2>Photo captured with ESP32-CAM and attached in this email.</h2>";
  message.html.content = htmlMsg.c_str();
  message.html.charSet = "utf-8";
  message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp;

  message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal;
  message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay;

  /* The attachment data item */
  SMTP_Attachment att;

  /** Set the attachment info e.g.
   * file name, MIME type, file path, file storage type,
   * transfer encoding and content encoding
  */
  att.descr.filename = FILE_PHOTO;
  att.descr.mime = "image/png";
  att.file.path = FILE_PHOTO_PATH;
  att.file.storage_type = esp_mail_file_storage_type_flash;
  att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;

  /* Add attachment to the message */
  message.addAttachment(att);

  /* Connect to server with the session config */
  if (!smtp.connect(&config))
    return;

  /* Start sending the Email and close the session */
  if (!MailClient.sendMail(&smtp, &message, true))
    Serial.println("Error sending Email, " + smtp.errorReason());
}

// Callback function to get the Email sending status
void smtpCallback(SMTP_Status status){
  /* Print the current status */
  Serial.println(status.info());

  /* Print the sending result */
  if (status.success())
  {
    Serial.println("----------------");
    Serial.printf("Message sent success: %d\n", status.completedCount());
    Serial.printf("Message sent failled: %d\n", status.failedCount());
    Serial.println("----------------\n");
    struct tm dt;

    for (size_t i = 0; i < smtp.sendingResult.size(); i++){
      /* Get the result item */
      SMTP_Result result = smtp.sendingResult.getItem(i);
      time_t ts = (time_t)result.timestamp;
      localtime_r(&ts, &dt);

      ESP_MAIL_PRINTF("Message No: %d\n", i + 1);
      ESP_MAIL_PRINTF("Status: %s\n", result.completed ? "success" : "failed");
      ESP_MAIL_PRINTF("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec);
      ESP_MAIL_PRINTF("Recipient: %s\n", result.recipients.c_str());
      ESP_MAIL_PRINTF("Subject: %s\n", result.subject.c_str());
    }
    Serial.println("----------------\n");

   // You need to clear sending result as the memory usage will grow up.
   smtp.sendingResult.clear();
  }
}

Исходный код

Как работает код

Продолжайте читать, чтобы узнать, как работает код, или перейдите к разделу Демонстрация. Не забудьте вставить свои сетевые учётные данные и настройки email в код. Также, если вы используете модель камеры, отличную от ESP32-CAM AI-Thinker, не забудьте изменить назначение пинов.

Импорт библиотек

Импортируйте необходимые библиотеки. ESP_Mail_Client.h используется для отправки писем, FS.h используется для доступа и сохранения файлов в LittleFS, а библиотека WiFi.h используется для инициализации Wi-Fi и подключения вашего ESP32-CAM к локальной сети.

#include "esp_camera.h"
#include "SPI.h"
#include "driver/rtc_io.h"
#include <ESP_Mail_Client.h>
#include <FS.h>
#include <WiFi.h>

Сетевые учётные данные

Вставьте ваши сетевые учётные данные в следующие переменные:

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Настройки Email

Введите email-аккаунт отправителя в переменную emailSenderAccount и его пароль в переменную emailSenderPassword.

#define emailSenderAccount   "EXAMPLE_SENDER_ACCOUNT@gmail.com"
#define emailSenderPassword  "SENDER_ACCOUNT_PASSWORD"

Вставьте email получателя. Это адрес, на который будут приходить письма, отправленные ESP32:

#define emailRecipient "YOUR_EMAIL_RECIPIENT@gmail.com"

Вставьте настройки SMTP вашего почтового провайдера в следующие строки. Мы используем настройки для аккаунта Gmail. Если вы используете другого почтового провайдера, замените на соответствующие настройки SMTP.

#define smtpServer "smtp.gmail.com"
#define smtpServerPort 465

Напишите тему письма в переменной emailSubject.

#define emailSubject "ESP32-CAM Photo Captured"

Создайте объект SMTPSession с именем smtp, который содержит данные для отправки по email и все остальные конфигурации.

/* The SMTP Session object used for Email sending */
SMTPSession smtp;

Фото, сделанное камерой ESP32, будет временно сохранено в LittleFS под именем photo.jpg в корневой директории.

#define FILE_PHOTO "photo.jpg"
#define FILE_PHOTO_PATH "/photo.jpg"

Пины камеры ESP32

Определите пины, используемые вашей моделью камеры. Мы используем ESP32-CAM AI-Thinker.

#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27

#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22

setup()

В setup() подключите ESP32 к Wi-Fi.

// Connect to Wi-Fi
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi...");
while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
}
Serial.println();

Выведите IP-адрес ESP32-CAM:

// Print ESP32 Local IP Address
Serial.print("IP Address: http://");
Serial.println(WiFi.localIP());

В setup() инициализируйте файловую систему, используя метод библиотеки ESP Mail Client. Файловая система по умолчанию, установленная в библиотеке для ESP32 – это LittleFS (вы можете изменить значение по умолчанию в файле библиотеки ESP_Mail_FS.h).

// Init filesystem
ESP_MAIL_DEFAULT_FLASH_FS.begin();

Следующие строки конфигурируют камеру и устанавливают настройки камеры:

camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sccb_sda = SIOD_GPIO_NUM;
config.pin_sccb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
config.grab_mode = CAMERA_GRAB_LATEST;

if(psramFound()){
  config.frame_size = FRAMESIZE_UXGA;
  config.jpeg_quality = 10;
  config.fb_count = 2;
} else {
  config.frame_size = FRAMESIZE_SVGA;
  config.jpeg_quality = 12;
  config.fb_count = 1;
}

Инициализируйте камеру.

// Initialize camera
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
  Serial.printf("Camera init failed with error 0x%x", err);
  return;
}

После инициализации камеры вызываются функции capturePhotoSaveLittleFS() и sendPhoto(). Эти функции определены в конце кода.

Функция capturePhotoSaveLittleFS()

Функция capturePhotoSaveLittleFS() делает фото и сохраняет его в ESP32 LittleFS. В следующих строках вы делаете фото и сохраняете его в буфере кадра (framebuffer) fb.

Примечание

Иногда первые фотографии, сделанные ESP32-CAM, получаются некачественными, потому что сенсор ещё не настроил баланс белого. Поэтому, чтобы получить хорошее фото, мы отбрасываем первые три снимка (это число может варьироваться в зависимости от вашей платы, поэтому настройте соответственно).

//Dispose first pictures because of bad quality
camera_fb_t* fb = NULL;
// Skip first 3 frames (increase/decrease number as needed).
for (int i = 0; i < 3; i++) {
  fb = esp_camera_fb_get();
  esp_camera_fb_return(fb);
  fb = NULL;
}

// Take a new photo
fb = NULL;
fb = esp_camera_fb_get();
if(!fb) {
  Serial.println("Camera capture failed");
  delay(1000);
  ESP.restart();
}

Затем создайте новый файл в LittleFS, куда будет сохранено фото.

Serial.printf("Picture file name: %s\n", FILE_PHOTO_PATH);
File file = LittleFS.open(FILE_PHOTO_PATH, FILE_WRITE);

Проверьте, был ли файл успешно создан. Если нет, выведите сообщение об ошибке.

if (!file) {
  Serial.println("Failed to open file in writing mode");
}

Если новый файл был успешно создан, «скопируйте» изображение из буфера в этот новый файл.

file.write(fb->buf, fb->len); // payload (image), payload length
Serial.print("The picture has been saved in ");
Serial.print(FILE_PHOTO_PATH);
Serial.print(" - Size: ");
Serial.print(fb->len);
Serial.println(" bytes");

Закройте файл и очистите буфер для дальнейшего использования.

file.close();
esp_camera_fb_return(fb);

Функция sendPhoto()

После успешного сохранения фото в LittleFS, мы отправляем его по email, вызывая функцию sendPhoto(). Рассмотрим эту функцию.

void sendPhoto( void ) {

Включите отладку через последовательный порт для статуса email:

smtp.debug(1);

Установите функцию обратного вызова для получения результатов отправки:

smtp.callback(smtpCallback);

Объявите сессию email:

Session_Config config;

Настройте время, чтобы письмо имело правильную временную метку. Вам может потребоваться настроить переменную gmt_offset в зависимости от вашего местоположения.

/*Set the NTP config time
For times east of the Prime Meridian use 0-12
For times west of the Prime Meridian add 12 to the offset.
Ex. American/Denver GMT would be -6. 6 + 12 = 18
See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets
*/
config.time.ntp_server = F("pool.ntp.org,time.nist.gov");
config.time.gmt_offset = 0;
config.time.day_light_offset = 1;

Установите хост сервера, порт, email отправителя и пароль для этой email-сессии:

/* Set the session config */
config.server.host_name = smtpServer;
config.server.port = smtpServerPort;
config.login.email = emailSenderAccount;
config.login.password = emailSenderPassword;
config.login.user_domain = "";

Объявите класс SMTP_Message:

SMTP_Message message;

Установите заголовки сообщения – имя отправителя, email отправителя, тему и получателя (вы можете изменить имя получателя):

/* Set the message headers */
message.sender.name = "ESP32-CAM";
message.sender.email = emailSenderAccount;

message.subject = emailSubject;
message.addRecipient("Sara", emailRecipient);

В следующих строках установите содержимое сообщения в переменной htmlMsg:

String htmlMsg = "<h2>Photo captured with ESP32-CAM and attached in this email.</h2>";
message.html.content = htmlMsg.c_str();
message.html.charSet = "utf-8";
message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp;

Теперь нужно позаботиться о вложениях. Создайте вложение:

SMTP_Attachment att;

Установите информацию о вложении: имя файла, MIME-тип, путь к файлу и где хранится содержимое (в нашем случае оно сохранено во flash (esp_mail_file_storage_type_flash)):

att.descr.filename = FILE_PHOTO;
att.descr.mime = "image/png";
att.file.path = FILE_PHOTO_PATH;
att.file.storage_type = esp_mail_file_storage_type_flash;
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;

Добавьте вложение к сообщению:

/* Add attachment to the message */
message.addAttachment(att);

Подключитесь к SMTP-серверу:

/* Connect to server with the session config */
if (!smtp.connect(&config))
  return;

Наконец, следующие строки отправляют сообщение:

/* Start sending the Email and close the session */
if (!MailClient.sendMail(&smtp, &message, true))
  Serial.println("Error sending Email, " + smtp.errorReason());

В этом примере письмо отправляется один раз при загрузке ESP32, поэтому loop() пуст.

void loop() {}

Чтобы отправить новое письмо, вам просто нужно перезагрузить плату (нажмите встроенную кнопку RESET).

Демонстрация

После внесения необходимых изменений в код: распиновка камеры, email-адрес отправителя, пароль email отправителя, email-адрес получателя и сетевые учётные данные, вы можете загрузить код на свою плату.

Если вы не знаете, как загрузить код на ESP32-CAM, прочитайте следующую статью:

После загрузки откройте Serial Monitor и нажмите кнопку RESET на ESP32-CAM. ESP32 должен подключиться к Wi-Fi, сделать фото, сохранить его в LittleFS, подключиться к SMTP-серверу и отправить письмо, как показано ниже.

Отправка Email ESP32-CAM Serial Monitor

Через несколько секунд вы должны получить новое письмо от ESP32-CAM в своём почтовом ящике. Как видно на изображении ниже, имя отправителя – «ESP32-CAM», как мы определили в коде, а тема – «ESP32-CAM Photo Captured».

ESP32-CAM Email с фото получено во входящих

Откройте письмо, и вы увидите фото, снятое ESP32-CAM.

ESP32-CAM отправка фото на Email Gmail входящие

Вы можете открыть или скачать фото, чтобы увидеть его в полном размере.

Фото сделанное ESP32-CAM в полном размере

Заключение

В этом руководстве вы узнали, как отправлять письма с фотографиями, сделанными ESP32-CAM. Представленный пример максимально прост: он делает фото и отправляет его по email при первой загрузке ESP32-CAM. Для отправки нового письма нужно перезагрузить плату.

Этот проект не имеет практического применения сам по себе, но он полезен для понимания того, как отправить email с вложением. После этого должно быть довольно легко добавить эту функцию в ваши собственные проекты ESP32-CAM.

Другие проекты с ESP32-CAM, которые могут вам понравиться: