ESP32-CAM: Take and Send Photos via Email using an SMTP Server

This tutorial shows how to send captured photos from the ESP32-CAM to your email account using an SMTP Server. We’ll show you a simple example that takes a photo when the ESP32 boots and sends it as an attachment in an email. The last photo taken is temporarily saved in the ESP32 SPIFFS.

ESP32-CAM Take and Send Photos via Email using an SMTP Server Arduino IDE

To make this project work, the ESP32-CAM needs to be connected to a router with access to the internet – needs to be connected to your local network.

This project is compatible with any ESP32 camera board with the OV2640 camera. You just need to make sure you use the right pin assignment for the board you’re using: ESP32-CAM Camera Boards: Pin and GPIOs Assignment Guide.

ESP32 MailClient Library

To send emails with the ESP32-CAM, we’ll use the ESP32 MailClient library. This library allows the ESP32 to send and receive emails with or without attachment via SMTP and IMAP servers.

In this project, we’ll use SMTP to send an email with an attachment. The attachment is a photo taken with the ESP32-CAM.

SMTP means Simple Mail Transfer Protocol and it is an internet standard for email transmission. To send emails through code, you need to know your SMTP server details. Each email provider has a different SMTP server.

Installing the ESP32 MailClient Library

Before proceeding with this tutorial, you need to install the ESP32 MailClient library. This library can be installed through the Arduino IDE Library Manager.

In your Arduino IDE go to Sketch > Include Library > Manage Libraries…

The Library Manager should open. Search for ESP32 Mail Client by Mobizt and install the library as shown below.

Install library ESP32 Send Email SMTP Server Arduino IDE

Sender Email (New Account)

We recommend creating a new email account to send the emails to your main personal email address. Do not use your main personal email to send emails via ESP32. If something goes wrong in your code or if by mistake you make too many requests, you can be banned or have your account temporary disabled.

We’ll use a newly created Gmail.com account to send the emails, but you can use any other email provider. The receiver email can be your personal email without any problem.

Create a Sender Email Account

Create a new email account for sending emails with the ESP32. If you want to use a Gmail account, go to this link to create a new one.

Gmail Create a new account

Create an App Password

You need to create an app password so that the ESP32 is able to send emails using your Gmail account. An App Password is a 16-digit passcode that gives a less secure app or device permission to access your Google Account. Learn more about sign-in with app passwords here.

An app password can only be used with accounts that have 2-step verification turned on.

  1. Open your Google Account.
  2. In the navigation panel, select Security.
  3. Under “Signing in to Google,” select 2-Step Verification > Get started.
  4. Follow the on-screen steps.

After enabling 2-step verification, you can create an app password.

  1. Open your Google Account.
  2. In the navigation panel, select Security.
  3. Under “Signing in to Google,” select App Passwords.
Create app password gmail
  1. In the Select app field, choose mail. For the device, select Other and give it a name, for example ESP32. Then, click on Generate. It will pop-up a window with a password that you’ll use with the ESP32 or ESP8266 to send emails. Save that password (even though it says you won’t need to remmeber it) because you’ll need it later.
Generated App password gmail

Now, you should have an app password that you’ll use on the ESP32 code to send the emails.

Gmail app password created for ESP32 send emails

If you’re using another email provider, check what you need to do to allow less secure apps. You should be able to find the instructions with a quick google search “your_email_provider + allow less secure apps”.

Gmail SMTP Server Settings

If you’re using a Gmail account, these are the SMTP Server details:

  • SMTP Server: smtp.gmail.com
  • SMTP username: Complete Gmail address
  • SMTP password: Your Gmail password
  • SMTP port (TLS): 587
  • SMTP port (SSL): 465
  • SMTP TLS/SSL required: yes

Outlook SMTP Server Settings

For Outlook accounts, these are the SMTP Server settings:

  • SMTP Server: smtp.office365.com
  • SMTP Username: Complete Outlook email address
  • SMTP Password: Your Outlook password
  • SMTP Port: 587
  • SMTP TLS/SSL Required: Yes

Live or Hotmail SMTP Server Settings

For Live or Hotmail accounts, these are the SMTP Server settings:

  • SMTP Server: smtp.live.com
  • SMTP Username: Complete Live/Hotmail email address
  • SMTP Password: Your Windows Live Hotmail password
  • SMTP Port: 587
  • SMTP TLS/SSL Required: Yes

If you’re using another email provider, you need to search for its SMTP Server settings. Now, you have everything ready to start sending emails with the ESP32-CAM.

Code – ESP32-CAM Send Email

The following code takes a photo when the ESP32-CAM first boots and sends it to your email account. Before uploading the code, make sure you insert your sender email settings as well as your recipient email.

/*********
  Rui Santos
  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 "ESP32_MailClient.h"
#include <FS.h>
#include <SPIFFS.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 Emails using Gmail on port 465 (SSL), you need to create an app password: https://support.google.com/accounts/answer/185833
#define emailSenderAccount    "[email protected]"
#define emailSenderPassword   "SENDER_ACCOUNT_PASSWORD"
#define smtpServer            "smtp.gmail.com"
#define smtpServerPort        465
#define emailSubject          "ESP32-CAM Photo Captured"
#define emailRecipient        "[email protected]"

#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 Email Sending data object contains config and data to send
SMTPData smtpData;

// Photo File Name to save in SPIFFS
#define FILE_PHOTO "/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();
  
  if (!SPIFFS.begin(true)) {
    Serial.println("An Error has occurred while mounting SPIFFS");
    ESP.restart();
  }
  else {
    delay(500);
    Serial.println("SPIFFS mounted successfully");
  }
  
  // Print ESP32 Local IP Address
  Serial.print("IP Address: http://");
  Serial.println(WiFi.localIP());
   
  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_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_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;
  
  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;
  }
  
  capturePhotoSaveSpiffs();
  sendPhoto();
}

void loop() {

}

// Check if photo capture was successful
bool checkPhoto( fs::FS &fs ) {
  File f_pic = fs.open( FILE_PHOTO );
  unsigned int pic_sz = f_pic.size();
  return ( pic_sz > 100 );
}

// Capture Photo and Save it to SPIFFS
void capturePhotoSaveSpiffs( void ) {
  camera_fb_t * fb = NULL; // pointer
  bool ok = 0; // Boolean indicating if the picture has been taken correctly

  do {
    // Take a photo with the camera
    Serial.println("Taking a photo...");

    fb = esp_camera_fb_get();
    if (!fb) {
      Serial.println("Camera capture failed");
      return;
    }

    // Photo file name
    Serial.printf("Picture file name: %s\n", FILE_PHOTO);
    File file = SPIFFS.open(FILE_PHOTO, 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);
      Serial.print(" - Size: ");
      Serial.print(file.size());
      Serial.println(" bytes");
    }
    // Close the file
    file.close();
    esp_camera_fb_return(fb);

    // check if file has been correctly saved in SPIFFS
    ok = checkPhoto(SPIFFS);
  } while ( !ok );
}

void sendPhoto( void ) {
  // Preparing email
  Serial.println("Sending email...");
  // Set the SMTP Server Email host, port, account and password
  smtpData.setLogin(smtpServer, smtpServerPort, emailSenderAccount, emailSenderPassword);
  
  // Set the sender name and Email
  smtpData.setSender("ESP32-CAM", emailSenderAccount);
  
  // Set Email priority or importance High, Normal, Low or 1 to 5 (1 is highest)
  smtpData.setPriority("High");

  // Set the subject
  smtpData.setSubject(emailSubject);
    
  // Set the email message in HTML format
  smtpData.setMessage("<h2>Photo captured with ESP32-CAM and attached in this email.</h2>", true);
  // Set the email message in text format
  //smtpData.setMessage("Photo captured with ESP32-CAM and attached in this email.", false);

  // Add recipients, can add more than one recipient
  smtpData.addRecipient(emailRecipient);
  //smtpData.addRecipient(emailRecipient2);

  // Add attach files from SPIFFS
  smtpData.addAttachFile(FILE_PHOTO, "image/jpg");
  // Set the storage type to attach files in your email (SPIFFS)
  smtpData.setFileStorageType(MailClientStorageType::SPIFFS);

  smtpData.setSendCallback(sendCallback);
  
  // Start sending Email, can be set callback function to track the status
  if (!MailClient.sendMail(smtpData))
    Serial.println("Error sending Email, " + MailClient.smtpErrorReason());

  // Clear all data from Email object to free memory
  smtpData.empty();
}

// Callback function to get the Email sending status
void sendCallback(SendStatus msg) {
  //Print the current status
  Serial.println(msg.info());
}

View raw code

How the Code Works

Continue reading to learn how the code works, or skip to the Demonstration section. Don’t forget to insert your network credentials and email settings in the code. Also, if you’re using a camera model other than an ESP32-CAM AI-Thinker, don’t forget to change the pin assignment.

Importing Libraries

Import the required libraries. The ESP32_MailClient.h is used to send emails, the FS.h and SPIFFS.h are used to access and save files to SPIFFS and the WiFi.h library is used to initialize Wi-Fi and connect your ESP32-CAM to your local network.

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

Network Credentials

Insert your network credentials in the following variables:

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

Email Settings

Type the email sender account on the emailSenderAccount variable and its password on the emailSenderPassword variable.

#define emailSenderAccount   "[email protected]"
#define emailSenderPassword  "SENDER_ACCOUNT_PASSWORD"

Insert the recipient’s email. This is the email that will receive the emails sent by the ESP32:

#define emailRecipient "[email protected]"

Insert your email provider SMTP settings on the following lines. We’re using the settings for a Gmail account. If you’re using a different email provider, replace with the corresponding SMTP settings.

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

Write the email subject on the emailSubject variable.

#define emailSubject "ESP32-CAM Photo Captured"

Create an STMPData object called smtpData that contains the data to send via email and all the other configurations.

SMTPData smtpData;

The photo taken with the ESP32 camera will be temporarily saved in SPIFFS under the name photo.jpg.

define FILE_PHOTO "/photo.jpg"

ESP32 Camera Pins

Define the pins used by your camera model. We’re using the 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()

In the setup(), connect the ESP32 to 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();

Initialize SPIFFS (SPI Flash File System) to save the last photo taken with the ESP32-CAM.

if (!SPIFFS.begin(true)) {
  Serial.println("An Error has occurred while mounting SPIFFS");
  ESP.restart();
}
else {
  delay(500);
  Serial.println("SPIFFS mounted successfully");
}

Print the ESP32-CAM IP address:

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

The following lines configure the camera and set the camera settings:

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_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_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;

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 the camera.

// 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;
}

After initializing the camera, call the capturePhotoSaveSpiffs() and the sendPhoto() functions. These functions are defined at the end of the code.

capturePhotoSaveSpiffs() function

The capturePhotoSaveSpiffs() function captures a photo and saves it in the ESP32 SPIFFS. In the following lines, you take a photo and save it in the framebuffer fb:

fb = esp_camera_fb_get();
if (!fb) {
  Serial.println("Camera capture failed");
  return;
}

Then, create a new file in SPIFFS where the photo will be saved.

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

Check if the file was successfully created. If not, print an error message.

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

If a new file was successfully created, “copy” the image from the buffer to that newly created file.

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

Close the file and clear the buffer for future use.

file.close();
esp_camera_fb_return(fb);

Finally, check whether the photo was successfully taken and saved. We can do that by checking the photo file size with the checkPhoto() function.

ok = checkPhoto(SPIFFS);

The checkPhoto() function, checks the file picture size. If the picture size is bigger than 100 bytes, it’s almost certain the photo was taken and saved successfully. In that case it returns 1.

bool checkPhoto( fs::FS &fs ) {
  File f_pic = fs.open( FILE_PHOTO );
  unsigned int pic_sz = f_pic.size();
  return ( pic_sz > 100 );
}

So, the ok variable is equal to 1.

ok = checkPhoto(SPIFFS);

In case the photo size is less than 100 bytes, the ok variable will continue to be 0, and it will keep trying to take a new photo and save it.

sendPhoto() function

After having the photo successfully saved in SPIFFS, we’ll send it via email by calling the sendPhoto() function. Let’s take a look at that function.

void sendPhoto( void ) {

The following line sets the SMTP Server host, SMTP port, account email address and password used to login:

smtpData.setLogin(smtpServer, smtpServerPort, emailSenderAccount, emailSenderPassword);

Set the sender name and sender email. In this case, we’re setting the sender name to ESP32-CAM.

smtpData.setSender("ESP32-CAM", emailSenderAccount);

Set the email priority.

smtpData.setPriority("High");

Set the email subject.

smtpData.setSubject(emailSubject);

The following line sets the message. You can send an HTML text or raw text. In this case, we’re sending a message with some HTML.

smtpData.setMessage("<h2>Photo captured with ESP32-CAM and attached in this email.</h2>", true);

When sending a message in HTML format, you should pass true as a second parameter to the setMessage() method. If you want to send raw text, set false.

//smtpData.setMessage("Photo captured with ESP32-CAM and attached in this email.", false);

Finally, set the recipient email. This is the email that will receive the messages from the ESP32.

smtpData.addRecipient(emailRecipient);

Then, to attach a file, you just need to call the addAtatachFile() on the smtpData object and pass as argument the file path.

smtpData.addAttachFile(FILE_PHOTO, "image/jpg");

Finally, you need to set where your files are saved (SPIFFS or SD card). We’re using SPIFFS:

smtpData.setFileStorageType(MailClientStorageType::SPIFFS);

Set a callback function that will be called upon sending an email.

smtpData.setSendCallback(sendCallback);

The sendCallback() function returns whether the email was successfully sent or not.

Now that we’ve set all the details of the smtpData, we’re ready to send the email.

if (!MailClient.sendMail(smtpData))
  Serial.println("Error sending Email, " + MailClient.smtpErrorReason());

After sending the email, you can clear all the data from the smtpData object.

smtpData.empty();

In this example, the email is sent once when the ESP32 boots, that’s why the loop() is empty. The idea is to adapt the code to use in your own projects.

void loop() {

}

To send a new email. You just need to reset your board (press the on-board RESET
button), so that it restarts and runs the code again.

Demonstration

After making the necessary changes to the code: camera pinout, sender’s email address, sender’s email password, recipient’s email address and network credentials, you can upload the code to your board.

If you don’t know how to upload code to the ESP32-CAM, read the following post:

After uploading, open the Serial Monitor and press the ESP32-CAM RESET button. The ESP32 should connect to Wi-Fi, take a photo, save it in SPIFFS, connect to the SMTP server and send the email as shown below.

ESP32 CAM send photo via email serial monitor demonstration

After a few seconds, you should have a new email from the ESP32-CAM in your inbox. As you can see in the image below, the sender’s email name is “ESP32-CAM” as we’ve defined in the code and the subject “ESP32-CAM Photo Captured”.

ESP32 CAM Email with Photo Received Inbox

Open the email and you should see a photo captured by the ESP32-CAM.

ESP32 CAM Send Photo To Email Gmail Inbox

You can open or download the photo to see it in full size.

Photo taken with ESP32 CAM Full Size

Wrapping Up

In this tutorial you’ve learned how to send emails with photos taken with the ESP32-CAM. The example presented is as simple as possible: it takes a photo and sends it via email when the ESP32-CAM first boots. To send another email, you need to reset the board.

This project doesn’t have a practical application, but it is useful to understand how to send an email with an attachment. After this, it should be fairly easy to include this feature in your own ESP32-CAM projects.

Other ESP32-CAM projects you may like:

Learn more about the ESP32-CAM:

Thanks for reading.



Build Web Server projects with the ESP32 and ESP8266 boards to control outputs and monitor sensors remotely. Learn HTML, CSS, JavaScript and client-server communication protocols DOWNLOAD »

Build Web Server projects with the ESP32 and ESP8266 boards to control outputs and monitor sensors remotely. Learn HTML, CSS, JavaScript and client-server communication protocols DOWNLOAD »


Enjoyed this project? Stay updated by subscribing our newsletter!

69 thoughts on “ESP32-CAM: Take and Send Photos via Email using an SMTP Server”

      • Caden,
        Thanks for your reply.
        I am not an expert in IFTTT.
        Do you know if it is possible to ‘trigger’ the reset button remote with an IFTTT command which is required to start the capturing process?

        Thanks for your help in advance.
        BR
        Arjen

        Reply
        • Arjen, I did some research on IFTTT and they sadly don’t support sending data back to the ESP32-Cam chip, such as asking it to start capturing. I found another option, which would be to set up a server with the ESP32-Cam, and have it run a Event (handleRoot) when its address (Wifi.localIP()) is opened, or “triggered”.

          The code would be:

          /*********
          Rui Santos
          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 “ESP32_MailClient.h”
          #include <FS.h>
          #include <SPIFFS.h>
          #include <WiFi.h>
          #include <ESP8266WebServer.h>
          #include <ESP8266WiFi.h>
          #include <WiFiClient.h>

          // REPLACE WITH YOUR NETWORK CREDENTIALS
          const char* ssid = “REPLACE_WITH_YOUR_SSID”;
          const char* password = “REPLACE_WITH_YOUR_PASSWORD”;
          const char* host = “maker.ifttt.com”;
          //after you set up your account put your IFTTT key here. (see https://randomnerdtutorials.com/door-status-monitor-using-the-esp8266/)
          const char* apiKey = “YOUR_IFTTT_API_KEY”;

          // To send Email using Gmail use port 465 (SSL) and SMTP Server smtp.gmail.com
          // YOU MUST ENABLE less secure app option https://myaccount.google.com/lesssecureapps?pli=1
          #define emailSenderAccount “[email protected]
          #define emailSenderPassword “SENDER_ACCOUNT_PASSWORD”
          #define smtpServer “smtp.gmail.com”
          #define smtpServerPort 465
          #define emailSubject “ESP32-CAM Photo Captured”
          #define emailRecipient “[email protected]

          #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 Email Sending data object contains config and data to send
          SMTPData smtpData;

          // Photo File Name to save in SPIFFS
          #define FILE_PHOTO “/photo.jpg”

          void handleRoot() {
          //take capture and send via email.
          capturePhotoSaveSpiffs();
          sendPhoto();

          server.send(200, “text/plain”, “took capture and sent.”);
          }

          void handleNotFound() {
          digitalWrite(led, 1);
          String message = “File Not Found\n\n”;
          message += “URI: “;
          message += server.uri();
          message += “\nMethod: “;
          message += (server.method() == HTTP_GET) ? “GET” : “POST”;
          message += “\nArguments: “;
          message += server.args();
          message += “\n”;
          for (uint8_t i = 0; i < server.args(); i++) {
          message += ” ” + server.argName(i) + “: ” + server.arg(i) + “\n”;
          }
          server.send(404, “text/plain”, message);
          digitalWrite(led, 0);
          }

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

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

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

          if (!SPIFFS.begin(true)) {
          Serial.println(“An Error has occurred while mounting SPIFFS”);
          ESP.restart();
          }
          else {
          delay(500);
          Serial.println(“SPIFFS mounted successfully”);
          }

          // Print ESP32 Local IP Address
          //opening this will trigger a capture
          Serial.print(“IP Address: http://“);
          Serial.println(WiFi.localIP());

          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_sscb_sda = SIOD_GPIO_NUM;
          config.pin_sscb_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;

          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;
          }

          server.on(“/”, handleRoot);

          server.onNotFound(handleNotFound);

          server.begin();
          Serial.println(“HTTP server started! Ready to take photos.”);
          }

          void loop() {
          // in the original sketch this is empty.
          //now we just keep the server up to date.
          server.handleClient();
          MDNS.update();

          }

          // Check if photo capture was successful
          bool checkPhoto( fs::FS &fs ) {
          File f_pic = fs.open( FILE_PHOTO );
          unsigned int pic_sz = f_pic.size();
          return ( pic_sz > 100 );
          }

          // Capture Photo and Save it to SPIFFS
          void capturePhotoSaveSpiffs( void ) {
          camera_fb_t * fb = NULL; // pointer
          bool ok = 0; // Boolean indicating if the picture has been taken correctly

          do {
          // Take a photo with the camera
          Serial.println(“Taking a photo…”);

          fb = esp_camera_fb_get();
          if (!fb) {
          Serial.println("Camera capture failed");
          return;
          }

          // Photo file name
          Serial.printf("Picture file name: %s\n", FILE_PHOTO);
          File file = SPIFFS.open(FILE_PHOTO, 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);
          Serial.print(" - Size: ");
          Serial.print(file.size());
          Serial.println(" bytes");
          }
          // Close the file
          file.close();
          esp_camera_fb_return(fb);

          // check if file has been correctly saved in SPIFFS
          ok = checkPhoto(SPIFFS);

          } while ( !ok );
          }

          void sendPhoto( void ) {
          // Preparing email
          Serial.println(“Sending email…”);
          // Set the SMTP Server Email host, port, account and password
          smtpData.setLogin(smtpServer, smtpServerPort, emailSenderAccount, emailSenderPassword);

          // Set the sender name and Email
          smtpData.setSender(“ESP32-CAM”, emailSenderAccount);

          // Set Email priority or importance High, Normal, Low or 1 to 5 (1 is highest)
          smtpData.setPriority(“High”);

          // Set the subject
          smtpData.setSubject(emailSubject);

          // Set the email message in HTML format
          smtpData.setMessage(”

          Photo captured with ESP32-CAM and attached in this email.

          “, true);
          // Set the email message in text format
          //smtpData.setMessage(“Photo captured with ESP32-CAM and attached in this email.”, false);

          // Add recipients, can add more than one recipient
          smtpData.addRecipient(emailRecipient);
          //smtpData.addRecipient(emailRecipient2);

          // Add attach files from SPIFFS
          smtpData.addAttachFile(FILE_PHOTO, “image/jpg”);
          // Set the storage type to attach files in your email (SPIFFS)
          smtpData.setFileStorageType(MailClientStorageType::SPIFFS);

          smtpData.setSendCallback(sendCallback);

          // Start sending Email, can be set callback function to track the status
          if (!MailClient.sendMail(smtpData))
          Serial.println(“Error sending Email, ” + MailClient.smtpErrorReason());

          // Clear all data from Email object to free memory
          smtpData.empty();
          }

          // Callback function to get the Email sending status
          void sendCallback(SendStatus msg) {
          //Print the current status
          Serial.println(msg.info());
          }

          Reply
        • Create a function that calls capturePhotoSaveSpiffs() and sendPhoto() whenever you send an IFFT trigger to it, then put this function inside main loop(). You wouldn’t need that “reset” function.

          Reply
          • sirDaniel’s idea would work if IFTTT had a way to trigger the capturePhotoSaveSpiffs() and sendPhoto() function. might be able to if you use webhooks request.

  1. These two methods are what you want to call when the web URL is triggered:

    capturePhotoSaveSpiffs();
    sendPhoto();

    you might have to create your own applet.

    The idea would be that you set up a web server, and the IFTTT applet would send info to the server when a web URL is opened.

    Reply
  2. Hi Rui and Sara,
    Great post with interesting features for other projects!
    It would be really interesting in future posts to present the code part of the post on both the arduino IDE and also MicroPython.
    Do you thing it might be possible?
    Regards
    Alain

    Reply
    • Hi.
      Thanks for your comment.
      We intend to do some projects with the ESP32-CAM and MicroPython.
      However, I don’t know when they’ll be ready.
      Regards,
      Sara

      Reply
  3. Hi,
    I tried this project and could download to the ESP.
    In the serial monitor I can see that it do all until connect to the smtp server.
    There is an error : Error, could not connect to server.
    I have activated as mentioned the lower security of the new created gmail account.
    What can I do now?
    Thank You and Best Regards
    Michael

    16:15:57.346 -> Connecting to WiFi….
    16:15:58.510 -> SPIFFS mounted successfully
    16:15:58.510 -> IP Address: http://192.168.100.242
    16:15:59.193 -> Taking a photo…
    16:15:59.501 -> Picture file name: /photo.jpg
    16:16:01.075 -> The picture has been saved in /photo.jpg – Size: 145792 bytes
    16:16:01.110 -> Sending email…
    16:16:01.110 -> Connecting to SMTP server…
    16:16:01.110 -> Error, could not connect to server
    16:16:01.110 -> Error sending Email, could not connect to server

    #define smtpServer “smtp.gmail.com”
    #define smtpServerPort 465
    #define emailSubject “ESP32-CAM Photo Captured”

    can ping the ESP in my WiFi Network and it has internet access.

    Reply
  4. WOW.. I just found this site and the many articles covering the ESP32 Cam.. So I see capture and save, capture and email, a PIR triggered send to telegram.. Has anyone done a PIR Capture, save to SD and Email yet?? I am waiting on my board, but hope to achieve this for my board..

    Reply
  5. hello, I want to thank you for your work.
    I would like to know if we can add an HC-SR501 PIR Motion Sensor Module as for telegram.
    Thank you for your reply

    Reply
  6. hi there
    Thanks for great instructions !!
    At the end, after reset the board, on my COM4 monitor I always(!) receive the same:

    d⸮⸮⸮⸮⸮888 g⸮{⸮⸮s⸮⸮KG

    May be someone can help… Thanks !

    Reply
  7. I always get this error in the serial terminal:

    [E][camera.c:1483] esp_camera_fb_get(): Failed to get the frame on time!

    And I receive the email with no photo attached.

    I think the problem is not the code because I have tried with the Web server example and that error happens too sometimes. I think the problem is any library… I have no idea. After searching on the Internet, it seems that problem is common (other people reported) but no clear instructions about how to solve it.

    I wonder if the SD card is the problem… And the camera is unable to store the photo.

    Reply
    • I found out the solution for my case, I hope many others can read this message because I have seen many people frustrated on the Internet with the error ” esp_camera_fb_get(): Failed to get the frame on time!”.

      Everything was solved just changing some parameters:


      config.xclk_freq_hz = 5000000;

      config.frame_size = FRAMESIZE_SVGA;

      If other people found other solution it worth sharing. Because I have seen it is a common issue.

      Reply
  8. I can’t make it work. I always get

    Connecting to SMTP server…
    Error, could not connect to server
    Error sending Email, could not connect to server

    All the credentials are properly set and I can send emails using the same credentials with other programs. What could be wrong?

    Many thanks in advance for any hint.

    Reply
      • Hi Sara, “muito obrigado” for your prompt answer, yes I’m using a Gmail account with Allow less secure apps ON, and I have ESP32 mail client V2.1.1 installed. I’ve tried with V2.1.6 but it failed exactly the same as before.

        Help me please! I really need to be able to send a picture from the ESPcam! (my application is for construction tracking)

        Thanks

        Reply
          • Olá Sara, yes it worked like a charm!

            So it seems this other library works better with Gmail, unfortunately I’m not that familiar with Arduino as to integrate both examples (the picture taking from the first example and the email part from the second) and would appreciate if you could assist on that. After all it will be a great update to your excellent tutorial.

            Obrigado e abraço!

          • Hi.
            I just tested the example and it works for me. I have the ESP32 Mail Client Library version 1.3.0 and ESP32 boards version 1.0.6 (you can check it in Tools > Boards > Boards Manager and search for ESP32).
            However, the ESP32 Mail Client Library is deprecated in favor of the ESPMailClient.
            So, here’s the example using the ESPMAilClient library instead: https://gist.github.com/sarasantos/30b520472b5f33a1af048b25b1798d12
            I didn’t update the tutorial yet because I need to clean up the code a bit before posting, but that link that I’ve sent you is working. I’ve tested it.
            I hope this helped.
            Regards,
            Sara

  9. Sara, I’m sorry but I’m still having problems 🙁

    My board version is the same as yours: 1.0.6

    ESP32 Mail Client Library I wasn’t able to find the same version you have (1.3.0) on the Library Managements it jumps from 1.2.3 to 2.0.0. Could you please double check your version?

    And using ESP Mail Client V1.3.0 running the last example it gives me the same error

    The picture has been saved in /photo.jpg – Size: 75648 bytes
    Connecting to SMTP server…

    C: ESP Mail Client v1.3.0
    C: connect to SMTP server
    C: host > smtp.gmail.com
    C: port > 465
    C: starting socket
    ! E: could not get ip from host
    C: cleaning SSL connection
    Error, unable to connect to server
    E: unable to connect to server

    I’m not sure what am I doing wrong…

    Reply
      • Dear Sara, I really appreciate your attention to help me.

        So I’ve exactly the same versions as you but in my case it works OK with the example with no picture attached and it can’t connect to the mail server when trying to send the picture.

        What else could I try? What could I have wrong?

        I have been fighting with this for two days now 🙁

        Reply
        • Sara, just one additional info that might help, I’ve tried with a different email service provider (UOL a very popular local service) and the issue was exactly the same

          The picture has been saved in /photo.jpg – Size: 156544 bytes
          Connecting to SMTP server…

          C: ESP Mail Client v1.3.0
          C: connect to SMTP server
          C: host > smtps.uol.com.br
          C: port > 465
          C: starting socket
          C: connecting to Server
          ! E: connect to Server failed!
          C: cleaning SSL connection
          Error, unable to connect to server
          E: unable to connect to server

          Reply
          • I’m sorry, I don’t know what else I can do to solve your issue.
            The project is working for me with the conditions I mentioned previously.
            Without further details, it is very difficult to find out what might be wrong.
            Regards,
            Sara

          • Sara, just as last resource could you please share with me your settings for the
            Board’s CPU Frequency and Flash Frequency ??

            May be there is something there, just guessing…

            Thanks

          • Hi.
            I don’t think that is relevant for the issue.
            But, here are my settings:
            CPU frequency: 240MHz (WiFi/BT)
            Flash Frequency: 80 MHz
            Regards,
            Sara

          • Hi Sara, just to share that my ESPcam was indeed with some kind of problem (very strange by the way) and the new board is working properly.

            Many thanks again for your help.

            Abraço

  10. Thanks Sara, as you expected it made no difference…

    I have ordered a new board because there is nothing else I can think of. Will report back if it works.

    Best

    Reply
    • ok.
      Thanks for keeping me updated.
      It can be a bad wi-fi connection. Try putting the board closer to your router.
      Regards,
      Sara

      Reply
  11. Hi Sara & Rui
    Your project is very cool.
    I really appreciate what you are doing.

    I am more and more drawn to this project and I am wondering if it is possible (and how) to make esp32-cam send a photo automatically every 24 hours?

    Thank you for your help
    Regards Adam

    Reply
  12. Hallo, kurze Anfrage: beim hochladen des codes wird mir folgender Fehler angezeigt:
    ……espressif\esp32/tools/esptool/esptool.exe”: file not exist
    Fehler beim Kompilieren für das Board AI Thinker ESP32-Cam

    Was muß ich tun ?

    LG
    XXAL

    Reply
  13. Hi,
    The email is sent OK with the pic attached but it keeps sending the same picture not an updated one. I want to send an updated pic continuously every half hour.

    All I changed/added to your code is:

    // capturePhotoSaveSpiffs();
    // sendPhoto();
    }

    void loop() {
    capturePhotoSaveSpiffs();
    sendPhoto();
    delay (1800000);
    }

    Thanks

    Reply
      • This does what I want. It send a pic every half hour if bright enough. Sends the updated pic then removes it from SPIFFS.
        It was sending only a partial or no pic so also added a SPIFFS format statement in the setup to correct this.

        bool formatted = SPIFFS.format(); //formats SPIFFS if corrupt and only partial picture

        void loop() {

        if (digitalRead(2) == LOW) digitalWrite(33, LOW); // TURN on LED if dark

        if (digitalRead(2) == HIGH) {
        digitalWrite(33, HIGH);

        delay (100);
        capturePhotoSaveSpiffs();
        delay (300);
        sendPhoto();
        SPIFFS.remove("FILE_PHOTO");
        delay (1800000);

        }

        Reply
  14. Hello there.

    I am keep taking this error

    sketch_feb14a:12:30: fatal error: ESP32_MailClient.h: No such file or directory
    compilation terminated.
    exit status 1
    ESP32_MailClient.h: No such file or directory

    I am trying to include ESP32_MailClient.h but it does nothing.
    does it happened to anyone else ?

    Thanks

    Reply
    • Hi.
      Are you sure you’re installing the right library?
      There are libraries with similar names that are not compatible.
      Regards,
      Sara

      Reply
      • Hello Sara.
        Thanks for the Reply.

        I searched on Library Manager for ESP 32 Mail client Libraries.
        I found two (2) libraries:
        ESP Mail Client (Version 2.0.3)
        ESP32 Mail Client. (Version 2.1.6)
        I installed both of them to be sure. but nothing happened.

        Just to be sure. I changed the ” ” with < > in the include. But the error is still there.

        If you have any idea of what it could be please inform me.

        Thanks for your time.

        Reply
        • Remove the ESP Mail Client library, and only use the ESP32 Mail Client.
          I’m not sure what might be causing the issue.
          Regards,
          Sara

          Reply
  15. Error, login password is not valid
    Error sending Email, login password is not valid

    Guess this is Google’s issue. It used to work properly when I completed the project. The ESP32 CAM was able to send photos and login without any issues. Thanks to Google, it’s no longer working. I can’t think of any other solutions other than trying other email providers.

    Reply
    • Hi.
      Double-check your credentials.
      And make sure you allow less secure apps in your account settings.
      Regards,
      Sara

      Reply
      • Hello Sara, thanks for the reply. Just to update, I found a solution for the issue I was facing not too long after posting the comment.

        Basically, I turned on 2 factor authentication and enabled something called “App Passwords”. Next, I generated a 16 pin password with app password and used that in the login credentials field inside the code. The project is able to send email again after doing those.

        I would recommend updating the steps for this tutorial. This is because by May 30 2022, ​​Google will no longer support the use of third-party apps or devices which ask you to sign in to your Google Account using only your username and password. Because of that, 2 factor and app password has to be used.

        Sorry for the late reply as I was busy and forgotten about replying.

        Link for screenshot reference regarding app password: https://drive.google.com/file/d/1mufB6QZtUB731LHnX2S4LONryEU30Bmb/view?usp=sharing

        Reply
        • Hi.
          Thanks for sharing.
          I’ll test that and update the tutorials that use gmail.
          Thank you so much.
          Regards,
          Sara

          Reply
  16. Great Project. I have added TTGO camera configuration and Sleep Mode:
    I thought I would share but excluded my credentials.

    /*
    // Pin definitions for My ESP32-CAM
    #define 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

    */

    // Pin definitions for CAMERA_MODEL_TTGO_WHITE (Mine)
    #define CAMERA_MODEL_TTGO_WHITE_BME280
    #define PWDN_GPIO_NUM 26
    #define RESET_GPIO_NUM -1
    #define XCLK_GPIO_NUM 32
    #define SIOD_GPIO_NUM 13
    #define SIOC_GPIO_NUM 12
    #define Y9_GPIO_NUM 39
    #define Y8_GPIO_NUM 36
    #define Y7_GPIO_NUM 23
    #define Y6_GPIO_NUM 18
    #define Y5_GPIO_NUM 15
    #define Y4_GPIO_NUM 4
    #define Y3_GPIO_NUM 14
    #define Y2_GPIO_NUM 5
    #define VSYNC_GPIO_NUM 27
    #define HREF_GPIO_NUM 25
    #define PCLK_GPIO_NUM 19

    // Photo File Name to save in SPIFFS
    #define PhotoFileName “/photo.jpg”

    String Filename() {
    return String(FILE).substring(String(FILE).lastIndexOf(“\”) + 1);
    }

    void setup() {
    Serial.begin(115200);
    delay(500);
    Serial.println(“\nProgram ~ ” + Filename());
    Serial.println(“Date Compiled ~ ” + String(DATE) + “\n”);

    // CONNECT to WiFi network:
    Serial.print(“WiFi Connecting to ” + String(ssid) + ” “);
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
    delay(300);
    Serial.print(“.”);
    }
    Serial.printf(” ~ Connected OK\n”);

    // Print the Signal Strength:
    long rssi = WiFi.RSSI() + 100;
    Serial.print(“Signal Strength = ” + String(rssi));
    if (rssi > 50) Serial.printf(” (>50 – Good)\n”); else Serial.printf(” (Could be Better)\n”);

    Serial.setDebugOutput(true);

    // Set Up SPIFFS
    SPIFFS.begin();
    if (!SPIFFS.begin(true)) {
    Serial.printf(“An Error has occurred while Mounting SPIFFS\n”);
    while (1) {
    delay(1000); // Stay here
    } else {
    Serial.printf(” ~ SPIFFS Mounted Successfully\n”);
    }
    }
    // Configure Camera Settings
    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_sscb_sda = SIOD_GPIO_NUM;
    config.pin_sscb_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;

    //Initial setting are FRAMESIZE_UXGA (320×240), Reset to SVGA (800×600)
    //Initalize with high specs to pre-allocate larger buffers
    if (psramFound()) {
    Serial.printf(” ~ PSRAM Found OK! Frame Set to SVGA\n”);
    config.frame_size = FRAMESIZE_SVGA; // (800×600)
    config.jpeg_quality = 10; // 10-63 lower number means higher quality
    config.fb_count = 2;
    } else {
    Serial.printf(“NO PSRAM found, Check Board Configuration !! Frame Set to UXGA\n”);
    config.frame_size = FRAMESIZE_UXGA; // (320×240)
    config.jpeg_quality = 12;
    config.fb_count = 2;
    }

    // Initialize Camera
    esp_err_t err = esp_camera_init(&config);
    if (err != ESP_OK) {
    if (err == 0x105) Serial.printf(“Check Camera Pins Configuration !!\n”);
    Serial.printf(“Camera init failed with error 0x%x”, err);
    return;
    }

    sensor_t * s = esp_camera_sensor_get();
    //Initial Image is flipped vertically/horzontally and colors are a bit saturated
    //s->set_vflip(s, 1); // Flip it back
    //s->set_brightness(s, 1); // Up the blightness just a bit
    //s->set_saturation(s, -2); // Lower the saturation

    if (s->id.PID == OV2640_PID) Serial.printf(” ~ Camera is OV2640\n”);
    if (s->id.PID == OV3660_PID) Serial.printf(” ~ Camera is OV3660\n”);
    if (s->id.PID == OV5640_PID) Serial.printf(” ~ Camera is OV5640\n”);

    Serial.printf(” ~ Camera Set Up OK!\n”);

    Serial.printf(“*******************************************\n”);

    Capture_Photo_Save_Spiffs();

    //Send_Photo(); // Moved “Send_Photo” at end of “Capture_Photo_Save_Spiffs”

    //Print the wakeup reason for ESP32
    Print_Wakeup_Reason();

    // EXTERNAL TRIGGER ~ GPIO_NUM_13 and Input High for ESP32-CAM
    esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 1); // 1 = High, 0 = Low

    // EXTERNAL TRIGGER ~ GPIO_NUM_33 and Input High for TTGO
    if (PWDN_GPIO_NUM == 26) { // for TTGO
    esp_sleep_enable_ext0_wakeup(GPIO_NUM_33, 1); // for TTGO
    }
    //If you were to use ext1, you would use it like:
    //esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

    // TIMED TRIGGER ~ First we configure the wake up source
    // We set our ESP32 to wake up every so many miliseconds (60 seconds) ~ TIMED TRIGGER
    //esp_sleep_enable_timer_wakeup(1000000 * 60));

    Serial.printf(“Going to Sleep now!\n”);
    Serial.flush();
    esp_deep_sleep_start();
    }

    void loop() {
    // Nothing to do here!!
    }

    void Print_Wakeup_Reason() {
    esp_sleep_wakeup_cause_t wakeup_reason;
    wakeup_reason = esp_sleep_get_wakeup_cause();
    Serial.printf(“\n”);
    switch (wakeup_reason) {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.printf(“Wakeup caused by EXTERNAL Signal using RTC_IO\n”); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.printf(“Wakeup caused by EXTERNAL Signal using RTC_CNTL\n”); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.printf(“Wakeup caused by TIMER\n”); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.printf(“Wakeup caused by Touchpad\n”); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println(“Wakeup caused by ULP program\n”); break;
    default : Serial.printf(“Wakeup was Not Caused by Deep Sleep: %d\n”, wakeup_reason); break;
    }
    }

    // Capture Photo and Save it to SPIFFS
    void Capture_Photo_Save_Spiffs( void ) {
    camera_fb_t * fb = NULL; // pointer
    bool ok = 0; // Boolean indicating if the picture has been taken correctly

    do {
    // Take a photo with the camera
    //fb = esp_camera_fb_get();
    camera_fb_t * fb = esp_camera_fb_get();
    if (!fb) {
    Serial.printf(“Camera capture FAILED\n”);
    return;
    }
    // Write data to the photo file
    File file = SPIFFS.open(PhotoFileName, “w+”); // Changed to “w+”
    // Check file
    if (!file) {
    Serial.printf(“FAILED to open file in writing mode\n”);
    return;
    } else {
    file.write(fb->buf, fb->len); // payload (image), payload length
    }
    // Close the file
    Serial.printf(“Successfully Saved as \t’%s’ – Size: %d bytes\n”, PhotoFileName, file.size());
    file.close();
    // Return the frame buffer back to the driver for reuse
    esp_camera_fb_return(fb);

    // check if file has been correctly saved in SPIFFS
    ok = Check_Photo(SPIFFS);

    } while ( !ok );
    Send_Photo();
    }

    // Check if photo capture was successful
    bool Check_Photo( fs::FS &fs ) {
    File f_pic = fs.open( PhotoFileName );
    unsigned int pic_sz = f_pic.size();
    Serial.printf(“Photo Verified as \t’%s’ – Size: %d bytes\n”, PhotoFileName, pic_sz);
    return ( pic_sz > 100 );
    }

    void Send_Photo( void ) {
    // Preparing email
    // Set the SMTP Server Email host, port, account and password
    smtpData.setLogin(smtpServer, smtpServerPort, emailSenderAccount, emailSenderPassword);

    // Set the sender name and Email
    smtpData.setSender(“ESP32-CAM”, emailSenderAccount);

    // Set Email priority or importance High, Normal, Low or 1 to 5 (1 is highest)
    smtpData.setPriority(“High”);

    // Set the subject
    smtpData.setSubject(emailSubject);

    // Set the email message in HTML format
    smtpData.setMessage(”

    Photo captured with ESP32-CAM and attached in this email.

    “, true);
    // Set the email message in text format
    //smtpData.setMessage(“Photo captured with ESP32-CAM and attached in this email.”, false);

    // Add recipients, can add more than one recipient
    smtpData.addRecipient(emailRecipient);
    //smtpData.addRecipient(emailRecipient2);

    // Add attach files from SPIFFS
    smtpData.addAttachFile(PhotoFileName, “image/jpg”);
    // Set the storage type to attach files in your email (SPIFFS)
    smtpData.setFileStorageType(MailClientStorageType::SPIFFS);

    smtpData.setSendCallback(sendCallback);

    // Start sending Email, can be set callback function to track the status
    if (!MailClient.sendMail(smtpData))
    Serial.printf(“Error sending Email %s\n”, MailClient.smtpErrorReason());

    // Clear all data from Email object to free memory
    smtpData.empty();
    }

    // Callback function to get the Email sending status
    void sendCallback(SendStatus msg) {
    //Print the current status
    Serial.println(msg.info());
    }

    Reply
  17. Hi,

    I’ve got a TTGO T-Camera (the white version, with a PIR) which won’t wake from deep sleep
    when powered via a 3.7V LiPo battery attached to the on-board battery connector.

    I have modified this sketch where the Camera goes to Sleep and then Wakes Up, either when PIR is triggered or after a wait period.

    Sleep/Wake behaves completely normally when powered via USB.

    Interestingly, I’ve noticed that when initially connecting the battery without USB power, the board also won’t power on until I’ve pressed RST.

    But with the battery attached and not powered via USB:
    If I let it sleep, then trigger a wake within a few seconds, it works.
    If I let it sleep, leave it for ~10 seconds or so, it will NOT Wake up again.

    Does anyone know how to fix this this issue?
    I tried adding:
    rtc_gpio_init(GPIO_NUM_14);
    rtc_gpio_set_direction(GPIO_NUM_14, RTC_GPIO_MODE_OUTPUT_ONLY);
    rtc_gpio_set_level(GPIO_NUM_14, 1);
    delay(500);
    But it doesn’t work.
    Any advice greatly appreciated!

    Reply
  18. #include “ESP32_MailClient.h” has been changed to #include <ESP_Mail_Client.h>
    I tried to use the first “include” statement and it comes up “not found”. Note the underscores between ESP and Mail, and Mail and Client.

    Reply
  19. Helo !
    Your’s tutorial is great. 🙂

    I have a problem.

    In code there is
    “define FILE_PHOTO “/photo.jpg”
    and
    #define emailSubject “Subkect”

    My question is, how can I set this names like this “/Photo_2022-06-05_13:00.jpg” or subject as “Subject _2022-06-05_13:00”
    Data and time is from actual time.

    Thanks for any help.
    All The Best

    Reply
  20. Hi.
    I wrote the program I wrote about earlier. However, I have a problem.
    ESP23-cam takes pictures of the gas meter 9 times a day. E.g. 23:59:00, 00:00:00 00:01:00 then 02:59:00, 03:00:00 then 05: 59: 00.06: 00: 00, 06:01:00 and so on . Why, so many photos for 1 hour – to be sure that one of the three will be correct.

    It happens that it takes 3 photos correctly, and sometimes only one. Sometimes the digits are half visible on one of them due to lack of light from backlight.
    Below come of the code in which the procedure is called take a photo

    // set of commands for each hour
    const char * Time_foto0 = “23:59:00”;
    const char * Time_foto01 = “00:00:00”;
    const char * Time_foto02 = “00:01:00”;
    e.t.c

    void loop(){
    if (strcmp (Time_, Time_foto0) == 0)
    digitalWrite (12, HIGH); // turn on the backlight
    capturePhotoSaveSpiffs ();
    digitalWrite (12, LOW); // turn off the backlight
    sendPhoto ();
    }
    if (strcmp (Time_, Time_foto01) == 0)
    digitalWrite (12, HIGH); // turn on the backlight
    capturePhotoSaveSpiffs ();
    digitalWrite (12, LOW); // turn off the backlight
    sendPhoto ();
    }
    e.t.c

    }

    Each fixed time triggers a set of commands. ESP takes a picture and sends it to gmail.
    Below are the settings and procedures
    Camera:
    void setup()
    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_sscb_sda = SIOD_GPIO_NUM;
    config.pin_sscb_scl = SIOC_GPIO_NUM;
    config.pin_pwdn = PWDN_GPIO_NUM;
    config.pin_reset = RESET_GPIO_NUM;
    //config.xclk_freq_hz = 20000000;
    config.xclk_freq_hz = 11000000;
    config.pixel_format = PIXFORMAT_JPEG;

    if (psramFound ()) {
    config.frame_size = FRAMESIZE_XGA; // UXGA; // UXGA;
    config.jpeg_quality = 7;
    config.fb_count = 2;
    } else {
    config.frame_size = FRAMESIZE_XGA; // SXGA;
    config.jpeg_quality = 77;
    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;
    }
    sensor_t * s = esp_camera_sensor_get ();
    s-> set_brightness (s, 0); // -2 is 2
    s-> set_contrast (s, 2); // -2 is 2
    s-> set_saturation (s, 0); // -2 is 2
    s-> set_special_effect (s, 0); // 0 to 6 (0 – No Effect, 1 – Negative, 2 – Grayscale, 3 – Red Tint, 4 – Green Tint, 5 – Blue Tint, 6 – Sepia)
    s-> set_whitebal (s, 1); // 0 = disable, 1 = enable
    s-> set_awb_gain (s, 1); // 0 = disable, 1 = enable
    s-> set_wb_mode (s, 0); // 0 to 4 – if awb_gain enabled (0 – Auto, 1 – Sunny, 2 – Cloudy, 3 – Office, 4 – Home)
    s-> set_exposure_ctrl (s, 1); // 0 = disable, 1 = enable
    s-> set_aec2 (s, 0); // 0 = disable, 1 = enable
    s-> set_ae_level (s, -1); // -2 is 2
    s-> set_aec_value (s, 300); // 0 to 1200
    s-> set_gain_ctrl (s, 1); // 0 = disable, 1 = enable
    s-> set_agc_gain (s, 0); // 0 to 30
    s-> set_gainceiling (s, (gainceiling_t) 0); // 0 is 6
    s-> set_bpc (s, 0); // 0 = disable, 1 = enable
    s-> set_wpc (s, 1); // 0 = disable, 1 = enable
    s-> set_raw_gma (s, 1); // 0 = disable, 1 = enable
    s-> set_lenc (s, 1); // 0 = disable, 1 = enable
    s-> set_hmirror (s, 0); // 0 = disable, 1 = enable
    s-> set_vflip (s, 1); // 0 = disable, 1 = enable
    s-> set_dcw (s, 1); // 0 = disable, 1 = enable
    s-> set_colorbar (s, 0); // 0 = disable, 1 = enable
    }

    // Check if photo capture was successful
    bool checkPhoto (fs :: FS & fs) {
    File f_pic = fs.open (“/” + FILE_PHOTO);
    unsigned int pic_sz = f_pic.size ();
    return (pic_sz> ​​100);
    }

    // Capture Photo and Save it to SPIFFS
    void capturePhotoSaveSpiffs (void) {
    camera_fb_t * fb = NULL; // pointer
    bool ok = 0; // Boolean indicating if the picture has been taken correctly

    to {
    // Take a photo with the camera
    Serial.println (“I’m taking a photo …”);

    delay (200);
    // Take a picture
    fb = esp_camera_fb_get ();
    // After doing
    if (! fb) {
    Serial.println ("Camera capture failed");
    return;
    }

    // Determine the file name
    Serial.printf ("Filename:", FILE_PHOTO);
    File file = SPIFFS.open ("/" + FILE_PHOTO, FILE_WRITE);

    // Put the data from the photo into the file
    if (! file) {
    Serial.println ("Problem with switching to writing mode");
    }
    else {
    file.write (fb-> buf, fb-> len); // payload (image), payload length
    Serial.print ("Picture Saved In");
    Serial.print ("/" + FILE_PHOTO);
    Serial.print ("- Size:");
    Serial.print (file.size ());
    Serial.println ("bytes");
    }
    // Close the file
    file.close ();
    esp_camera_fb_return (fb);
    // see if the file is saved correctly

    Is this config.xclk_freq_hz = 11000000; problem ?

    Thanks for help
    All The Best 4U

    Reply

Leave a Reply to Sara Santos Cancel reply

Download our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.