Gửi Email đính kèm tệp qua máy chủ SMTP trên ESP32

Trong bài trước, IoTZone đã hướng dẫn bạn cách gửi Email qua máy chủ SMTP, nhưng dưới dạng văn bản thô hoặc đoạn code HTML cơ bản. Trong bài này, chúng ta cũng tìm hiểu cách gửi Email đính kèm tệp tin hoặc hình ảnh (đuôi .png) nhé! Bạn có thể ứng dụng dự án này vào trong các dự án đọc thông tin từ cảm biến trong vài giờ hoặc gửi ảnh thu được từ kit Camera ESP32 AI.

Về cách cài thư viện hoặc cách tạo SMTP Server cơ bản, bạn xem bài trước nhé: Cách gửi Email bằng SMTP Server bằng ESP32: HTML hoặc văn bản

Tải tập tin lên LittleFS

Để gửi Email có đính kèm tệp, đầu tiên chúng ta phải lưu tập tin này trên hệ thống Filesystem của ESP32 hoặc trong thẻ nhớ microSD.

Dù bạn muốn gửi đính kèm tập tin nào hoặc hình ảnh nào, thì bạn cũng phải upload lên đó nhé! Mình thường sử dụng Plugin ESP32 Filesystem Uploader để up các tập tin này, thông qua phần mềm Arduino IDE. Bạn click vào link mình đã đính kèm để cài đặt plugin vào Arduino IDE nhé!

Sau khi cài xong, bạn click vào Sketch >> Show Scketch, tạo một thư mục bên trong và đặt tên là data. Sau đó, bạn hãy di chyển tập tin đính kèm hoặc hình ảnh cần đính kèm vào thư mục này.

Bạn cũng có thể click vào link này để tải thư mục dự án

Lưu ý: Với code mặc định, tập tin của bạn phải đặt là image.png và text_file.txt. Nếu thích đặt tên khác thì bạn có thể đặt, nhưng sau đó phải tùy biến trong code sao cho phù hợp nhé!

Cấu trúc của thư mục của bạn sẽ như bên dưới:

Cấu trúc thư mục để gửi Email trên ESP32 bằng máy chủ SMTP
Cấu trúc thư mục để gửi Email trên ESP32 bằng máy chủ SMTP

Sau khi di chuyển tập tin cần thiết vào thư mục data, bạn click vào Tools ESP32 Sketch Data Upload như hình dưới:

Click vào ESP32 Sketch Data Upload
Click vào ESP32 Sketch Data Upload

Sau đó, bạn chọn LittleFS và chờ vài phút để upload hình ảnh, tập tin lên nhé! Sau khi upload thành công, trên màn hình sẽ hiển thị một dòng tin nhắn báo thành công, bạn hãy đi tới bước tiếp theo – Nạp code để bắt đầu gửi email qua máy chủ SMTP trên ESP32 nhé!

Nạp code để gửi Email qua máy chủ SMTP

Chương trình bên dưới giúp bạn gửi Email có đính kèm tập tin văn bản .txt hoặc hình ảnh. Trước khi upload code vào ESP32, bạn nhớ thay đổi các thông tin như Email gửi, Email nhận,… nhé!

#include <Arduino.h>
#if defined(ESP32)
  #include <WiFi.h>
#elif defined(ESP8266)
  #include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>

#define WIFI_SSID "REPLACE_WITH_YOUR_SSID"
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD"

#define SMTP_HOST "smtp.gmail.com"

/** The smtp port e.g. 
 * 25  or esp_mail_smtp_port_25
 * 465 or esp_mail_smtp_port_465
 * 587 or esp_mail_smtp_port_587
*/
#define SMTP_PORT 465

/* The sign in credentials */
#define AUTHOR_EMAIL "YOUR_EMAIL@XXXX.com"
#define AUTHOR_PASSWORD "YOUR_EMAIL_APP_PASS"

/* Recipient's email*/
#define RECIPIENT_EMAIL "RECIPIENTE_EMAIL@XXXX.com"

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

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

void setup(){
  Serial.begin(115200);
  Serial.println();
  Serial.print("Connecting to AP");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED){
    Serial.print(".");
    delay(200);
  }
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  Serial.println();

  // Init filesystem
  ESP_MAIL_DEFAULT_FLASH_FS.begin();

  /** 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 for user defined session credentials */
  Session_Config config;

  /* Set the session config */
  config.server.host_name = SMTP_HOST;
  config.server.port = SMTP_PORT;
  config.login.email = AUTHOR_EMAIL;
  config.login.password = AUTHOR_PASSWORD;
  config.login.user_domain = "mydomain.net";
  
  /*
  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 = 3;
  config.time.day_light_offset = 0;

  /* 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 = "ESP Mail";
  message.sender.email = AUTHOR_EMAIL;

  message.subject = F("Test sending Email with attachments and inline images from Flash");
  message.addRecipient(F("Sara"), RECIPIENT_EMAIL);

  /** Two alternative content versions are sending in this example e.g. plain text and html */
  String htmlMsg = "This message contains attachments: image and text file.";
  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 = "image.png";
  att.descr.mime = "image/png"; //binary data
  att.file.path = "/image.png";
  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);

  message.resetAttachItem(att);
  att.descr.filename = "text_file.txt";
  att.descr.mime = "text/plain";
  att.file.path = "/text_file.txt";
  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)){
    ESP_MAIL_PRINTF("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str());
    return;
  }

  if (!smtp.isLoggedIn()){
    Serial.println("\nNot yet logged in.");
  }
  else{
    if (smtp.isAuthenticated())
      Serial.println("\nSuccessfully logged in.");
    else
      Serial.println("\nConnected with no Auth.");
  }

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

void loop(){
}

/* 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("----------------");
    ESP_MAIL_PRINTF("Message sent success: %d\n", status.completedCount());
    ESP_MAIL_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();
  }
}

Giải thích chương trình

Chương trình gửi Email có đính kèm tệp này khá tương tự với bài hướng dẫn trước, nên mình chỉ tập trung giải thích điểm khác biệt thôi nhé!

Trong setting(), chúng ta tạo hệ thống Filesystem bằng thư viện ESP Mail Client. Hệ thông tập tin mặc định lúc này là LittleFS, bạn có thể truy cập vào tệp thư viện ESP Mail FS.h để thay đổi tùy chọn này.

// Init filesystem
ESP_MAIL_DEFAULT_FLASH_FS.begin();

Tạo tập tin đính kèm:

/* The attachment data item */
SMTP_Attachment att;

Thêm các thông tin liên quan đến tập tin đính kèm, như tên, đường dẫn, loại lưu trữ và mã hóa đường truyền:

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

Thêm tập tin đính kèm vào Email gửi đi:

message.addAttachment(att);

Nếu bạn muốn gửi thêm 1 tập tin khác, bạn cần code dòng lệnh sau trước khi viết code đính kèm tập tin khác:

message.resetAttachItem(att);

Nhập thông tin chi tiết của tập tin đính kèm thứ 2, ở đây là tập tin text:

att.descr.filename = "text_file.txt";
att.descr.mime = "text/plain";
att.file.path = "/text_file.txt";
att.file.storage_type = esp_mail_file_storage_type_flash;
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;

Thêm tập tin đính kèm thứ hai này vào email gửi đi:

message.addAttachment(att);

Viết code để gửi tin nhắn dựa trên máy chủ SMTP như trong bài hướng dẫn trước đó:

if (!MailClient.sendMail(&smtp, &message, true))
  Serial.println("Error sending Email, " + smtp.errorReason());

Kết quả

Sau khi nạp code vào trong mạch ESP32, bạn hãy mở màn hình Serial Monitor ở tốc độ 115200, nhấn nút RST (Restart) trên mạch nhé!

Nếu code hoạt động đúng, bạn sẽ thấy dòng chữ sau xuất hiện trên màn hình Serial:

Demo kết quả gửi Email qua máy chủ SMTP trên ESP32

Lúc này, bạn hãy mở email nhận mà bạn đã code ra xem thử nhé, bạn sẽ thấy một Email có đính kèm 2 tệp như hình:

Cách gửi Email đính kèm tập tin, hình ảnh qua máy chủ SMTP
Cách gửi Email đính kèm tập tin, hình ảnh qua máy chủ SMTP

Lời kết

Vậy là chúng ta đã cùng đi qua hướng dẫn cách gửi Email có đính kèm tập tin hoặc hình ảnh từ ESP32, thông qua máy chủ SMTP. Chúc các bạn thành công!

Ở ví dụ trên thì mình setup cho gửi Email sau khi khởi động lại mạch ESP32. Tuy nhiên, bạn có thể tùy chỉnh lại sao cho phù hợp với nhu cầu, để sáng tạo dự án của bạn nhé! Chẳng hạn như khi nào nhận được hình ảnh từ Camera ESP32, đọc được thông tin từ cảm biến,… thì sẽ gửi Email kèm theo các thông tin này.

Trên Web IoTZone còn có nhiều tài liệu hướng dẫn khác thú vị về ESP32, bạn có thể tham khảo nếu thích:

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *