Quellcode durchsuchen

Merge branch 'example/simple_smtp_client' into 'master'

Added simple SMTP email client.

Closes IDF-1292

See merge request espressif/esp-idf!7309
Angus Gratton vor 6 Jahren
Ursprung
Commit
5c05af2641

+ 3 - 4
examples/protocols/openssl_client/main/openssl_client_example_main.c

@@ -37,10 +37,10 @@ static void openssl_example_task(void *p)
     struct sockaddr_in sock_addr;
     struct hostent *hp;
     struct ip4_addr *ip4_addr;
-    
+
     int recv_bytes = 0;
     char recv_buf[OPENSSL_EXAMPLE_RECV_BUF_LEN];
-    
+
     const char send_data[] = OPENSSL_EXAMPLE_REQUEST;
     const int send_bytes = sizeof(send_data);
 
@@ -134,7 +134,7 @@ static void openssl_example_task(void *p)
         recv_bytes += ret;
         ESP_LOGI(TAG, "%s", recv_buf);
     } while (1);
-    
+
     ESP_LOGI(TAG, "totally read %d bytes data from %s ......", recv_bytes, OPENSSL_EXAMPLE_TARGET_NAME);
 
 failed5:
@@ -172,7 +172,6 @@ static void openssl_example_client_init(void)
 
 void app_main(void)
 {
-    ESP_ERROR_CHECK( nvs_flash_init() );
     ESP_ERROR_CHECK(nvs_flash_init());
     ESP_ERROR_CHECK(esp_netif_init());
     ESP_ERROR_CHECK(esp_event_loop_create_default());

+ 9 - 0
examples/protocols/smtp_client/CMakeLists.txt

@@ -0,0 +1,9 @@
+# The following lines of boilerplate have to be in your project's CMakeLists
+# in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
+set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(smtp_client)

+ 10 - 0
examples/protocols/smtp_client/Makefile

@@ -0,0 +1,10 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := smtp_client
+
+EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
+
+include $(IDF_PATH)/make/project.mk

+ 78 - 0
examples/protocols/smtp_client/README.md

@@ -0,0 +1,78 @@
+# SMTP Client Example
+
+The Example is SMTP client demo. It sends and email with attachment to recipient.
+
+
+## How to use the example
+
+
+### Configure the project
+
+```
+idf.py menuconfig
+```
+
+* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../README.md) for more details.
+
+Please set the following parameters under example config for SMTP client demo to work:
+  - Email server, port, sender's email ID, password, recipient's email ID.
+
+
+### Build and Flash
+
+Build the project and flash it to the board, then run monitor tool to view serial output:
+
+```
+idf.py -p PORT flash monitor
+```
+
+(Replace PORT with the name of the serial port to use.)
+
+(To exit the serial monitor, type ``Ctrl-]``.)
+
+See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
+
+
+
+## Example output
+
+```
+I (3212) smtp_example: Loading the CA root certificate...
+I (3212) smtp_example: Setting hostname for TLS session...
+I (3222) smtp_example: Setting up the SSL/TLS structure...
+I (3232) smtp_example: Connecting to smtp.googlemail.com:587...
+I (3542) smtp_example: Connected.
+
+220 smtp.googlemail.com ESMTP r62sm20390571pfc.89 - gsmtp
+I (3952) smtp_example: Writing EHLO to server...
+
+250-smtp.googlemail.com at your service, [182.75.158.118]
+250-SIZE 35882577
+250-8BITMIME
+250-STARTTLS
+250-ENHANCEDSTATUSCOD
+ES
+250-PIPELINING
+250-CHUNKING
+250 SMTPUTF8
+I (4262) smtp_example: Writing STARTTLS to server...
+
+220 2.0.0 Ready to start TLS
+I (4562) smtp_example: Performing the SSL/TLS handshake...
+I (5692) smtp_example: Verifying peer X.509 certificate...
+I (5692) smtp_example: Certificate verified.
+I (5692) smtp_example: Cipher suite is TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256
+I (5702) smtp_example: Authentication...
+I (5702) smtp_example: Write AUTH LOGIN
+I (6002) smtp_example: Write USER NAME
+I (6302) smtp_example: Write PASSWORD
+I (6822) smtp_example: Write MAIL FROM
+I (7132) smtp_example: Write RCPT
+I (7432) smtp_example: Write DATA
+I (8252) smtp_example: Write Content
+I (10202) smtp_example: Email sent!
+```
+
+
+## Note:
+  - You might need to enable permission for less secure apps from email provider. This is because these email providers (e.g. gmail) insist on OAUTH authorization.

+ 2 - 0
examples/protocols/smtp_client/main/CMakeLists.txt

@@ -0,0 +1,2 @@
+idf_component_register(SRCS "smtp_client_example_main.c"
+                       EMBED_TXTFILES server_root_cert.pem esp_logo.png)

+ 33 - 0
examples/protocols/smtp_client/main/Kconfig.projbuild

@@ -0,0 +1,33 @@
+menu "Example Configuration"
+
+    config SMTP_SERVER
+        string "Mail Server"
+        default "smtp.googlemail.com"
+        help
+            Target domain for the example to connect to.
+
+    config SMTP_PORT_NUMBER
+        string "Mail port number"
+        default "587"
+        help
+            Mail port number for the example to connect to.
+
+    config SMTP_SENDER_MAIL
+        string "Sender email"
+        default "sender.email@gmail.com"
+        help
+            Sender's Email address
+
+    config SMTP_SENDER_PASSWORD
+        string "Sender password"
+        default "password@123"
+        help
+            Sender's email password
+
+    config SMTP_RECIPIENT_MAIL
+        string "Recipient email"
+        default "recipient.email@gmail.com"
+        help
+            Recipient's email
+
+endmenu

+ 5 - 0
examples/protocols/smtp_client/main/component.mk

@@ -0,0 +1,5 @@
+#
+# Main Makefile. This is basically the same as a component makefile.
+#
+
+COMPONENT_EMBED_TXTFILES := server_root_cert.pem esp_logo.png

BIN
examples/protocols/smtp_client/main/esp_logo.png


+ 25 - 0
examples/protocols/smtp_client/main/server_root_cert.pem

@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIESjCCAzKgAwIBAgINAeO0mqGNiqmBJWlQuDANBgkqhkiG9w0BAQsFADBMMSAw
+HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFs
+U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xNzA2MTUwMDAwNDJaFw0yMTEy
+MTUwMDAwNDJaMEIxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVHb29nbGUgVHJ1c3Qg
+U2VydmljZXMxEzARBgNVBAMTCkdUUyBDQSAxTzEwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQDQGM9F1IvN05zkQO9+tN1pIRvJzzyOTHW5DzEZhD2ePCnv
+UA0Qk28FgICfKqC9EksC4T2fWBYk/jCfC3R3VZMdS/dN4ZKCEPZRrAzDsiKUDzRr
+mBBJ5wudgzndIMYcLe/RGGFl5yODIKgjEv/SJH/UL+dEaltN11BmsK+eQmMF++Ac
+xGNhr59qM/9il71I2dN8FGfcddwuaej4bXhp0LcQBbjxMcI7JP0aM3T4I+DsaxmK
+FsbjzaTNC9uzpFlgOIg7rR25xoynUxv8vNmkq7zdPGHXkxWY7oG9j+JkRyBABk7X
+rJfoucBZEqFJJSPk7XA0LKW0Y3z5oz2D0c1tJKwHAgMBAAGjggEzMIIBLzAOBgNV
+HQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1Ud
+EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFJjR+G4Q68+b7GCfGJAboOt9Cf0rMB8G
+A1UdIwQYMBaAFJviB1dnHB7AagbeWbSaLd/cGYYuMDUGCCsGAQUFBwEBBCkwJzAl
+BggrBgEFBQcwAYYZaHR0cDovL29jc3AucGtpLmdvb2cvZ3NyMjAyBgNVHR8EKzAp
+MCegJaAjhiFodHRwOi8vY3JsLnBraS5nb29nL2dzcjIvZ3NyMi5jcmwwPwYDVR0g
+BDgwNjA0BgZngQwBAgIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly9wa2kuZ29vZy9y
+ZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAGoA+Nnn78y6pRjd9XlQWNa7H
+TgiZ/r3RNGkmUmYHPQq6Scti9PEajvwRT2iWTHQr02fesqOqBY2ETUwgZQ+lltoN
+FvhsO9tvBCOIazpswWC9aJ9xju4tWDQH8NVU6YZZ/XteDSGU9YzJqPjY8q3MDxrz
+mqepBCf5o8mw/wJ4a2G6xzUr6Fb6T8McDO22PLRL6u3M4Tzs3A2M1j6bykJYi8wW
+IRdAvKLWZu/axBVbzYmqmwkm5zLSDW5nIAJbELCQCZwMH56t2Dvqofxs6BBcCFIZ
+USpxu6x6td0V7SvJCCosirSmIatj/9dSSVDQibet8q/7UK4v4ZUN80atnZz1yg==
+-----END CERTIFICATE-----

+ 513 - 0
examples/protocols/smtp_client/main/smtp_client_example_main.c

@@ -0,0 +1,513 @@
+/**
+ * SMTP email client
+ *
+ * Adapted from the `ssl_mail_client` example in mbedtls.
+ *
+ * Original Copyright (C) 2006-2016, ARM Limited, All Rights Reserved, Apache 2.0 License.
+ * Additions Copyright (C) Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD, Apache 2.0 License.
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_event.h"
+#include "esp_log.h"
+#include "esp_system.h"
+#include "nvs_flash.h"
+#include "protocol_examples_common.h"
+
+#include "mbedtls/platform.h"
+#include "mbedtls/net_sockets.h"
+#include "mbedtls/esp_debug.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/error.h"
+#include "mbedtls/certs.h"
+#include <mbedtls/base64.h>
+#include <sys/param.h>
+
+
+/* Constants that are configurable in menuconfig */
+#define MAIL_SERVER         CONFIG_SMTP_SERVER
+#define MAIL_PORT           CONFIG_SMTP_PORT_NUMBER
+#define SENDER_MAIL         CONFIG_SMTP_SENDER_MAIL
+#define SENDER_PASSWORD     CONFIG_SMTP_SENDER_PASSWORD
+#define RECIPIENT_MAIL      CONFIG_SMTP_RECIPIENT_MAIL
+
+#define SERVER_USES_STARTSSL 1
+
+static const char *TAG = "smtp_example";
+
+#define TASK_STACK_SIZE     (8 * 1024)
+#define BUF_SIZE            512
+
+#define VALIDATE_MBEDTLS_RETURN(ret, min_valid_ret, max_valid_ret, goto_label)  \
+    do {                                                                        \
+        if (ret < min_valid_ret || ret > max_valid_ret) {                       \
+            goto goto_label;                                                    \
+        }                                                                       \
+    } while (0)                                                                 \
+
+/**
+ * Root cert for smtp.googlemail.com, taken from server_root_cert.pem
+ *
+ * The PEM file was extracted from the output of this command:
+ * openssl s_client -showcerts -connect smtp.googlemail.com:587 -starttls smtp
+ *
+ * The CA root cert is the last cert given in the chain of certs.
+ *
+ * To embed it in the app binary, the PEM file is named
+ * in the component.mk COMPONENT_EMBED_TXTFILES variable.
+ */
+
+extern const uint8_t server_root_cert_pem_start[] asm("_binary_server_root_cert_pem_start");
+extern const uint8_t server_root_cert_pem_end[]   asm("_binary_server_root_cert_pem_end");
+
+extern const uint8_t esp_logo_png_start[] asm("_binary_esp_logo_png_start");
+extern const uint8_t esp_logo_png_end[]   asm("_binary_esp_logo_png_end");
+
+static int write_and_get_response(mbedtls_net_context *sock_fd, unsigned char *buf, size_t len)
+{
+    int ret;
+    const size_t DATA_SIZE = 128;
+    unsigned char data[DATA_SIZE];
+    char code[4];
+    size_t i, idx = 0;
+
+    if (len) {
+        ESP_LOGD(TAG, "%s", buf);
+    }
+
+    if (len && (ret = mbedtls_net_send(sock_fd, buf, len)) <= 0) {
+        ESP_LOGE(TAG, "mbedtls_net_send failed with error -0x%x", -ret);
+        return ret;
+    }
+
+    do {
+        len = DATA_SIZE - 1;
+        ret = mbedtls_net_recv(sock_fd, data, len);
+
+        if (ret <= 0) {
+            ESP_LOGE(TAG, "mbedtls_net_recv failed with error -0x%x", -ret);
+            goto exit;
+        }
+
+        data[len] = '\0';
+        printf("\n%s", data);
+        len = ret;
+        for (i = 0; i < len; i++) {
+            if (data[i] != '\n') {
+                if (idx < 4) {
+                    code[idx++] = data[i];
+                }
+                continue;
+            }
+
+            if (idx == 4 && code[0] >= '0' && code[0] <= '9' && code[3] == ' ') {
+                code[3] = '\0';
+                ret = atoi(code);
+                goto exit;
+            }
+
+            idx = 0;
+        }
+    } while (1);
+
+exit:
+    return ret;
+}
+
+static int write_ssl_and_get_response(mbedtls_ssl_context *ssl, unsigned char *buf, size_t len)
+{
+    int ret;
+    const size_t DATA_SIZE = 128;
+    unsigned char data[DATA_SIZE];
+    char code[4];
+    size_t i, idx = 0;
+
+    if (len) {
+        ESP_LOGD(TAG, "%s", buf);
+    }
+
+    while (len && (ret = mbedtls_ssl_write(ssl, buf, len)) <= 0) {
+        if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+            ESP_LOGE(TAG, "mbedtls_ssl_write failed with error -0x%x", -ret);
+            goto exit;
+        }
+    }
+
+    do {
+        len = DATA_SIZE - 1;
+        ret = mbedtls_ssl_read(ssl, data, len);
+
+        if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+            continue;
+        }
+
+        if (ret <= 0) {
+            ESP_LOGE(TAG, "mbedtls_ssl_read failed with error -0x%x", -ret);
+            goto exit;
+        }
+
+        ESP_LOGD(TAG, "%s", data);
+
+        len = ret;
+        for (i = 0; i < len; i++) {
+            if (data[i] != '\n') {
+                if (idx < 4) {
+                    code[idx++] = data[i];
+                }
+                continue;
+            }
+
+            if (idx == 4 && code[0] >= '0' && code[0] <= '9' && code[3] == ' ') {
+                code[3] = '\0';
+                ret = atoi(code);
+                goto exit;
+            }
+
+            idx = 0;
+        }
+    } while (1);
+
+exit:
+    return ret;
+}
+
+static int write_ssl_data(mbedtls_ssl_context *ssl, unsigned char *buf, size_t len)
+{
+    int ret;
+
+    if (len) {
+        ESP_LOGD(TAG, "%s", buf);
+    }
+
+    while (len && (ret = mbedtls_ssl_write(ssl, buf, len)) <= 0) {
+        if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+            ESP_LOGE(TAG, "mbedtls_ssl_write failed with error -0x%x", -ret);
+            return ret;
+        }
+    }
+
+    return 0;
+}
+
+static int perform_tls_handshake(mbedtls_ssl_context *ssl)
+{
+    int ret = -1;
+    uint32_t flags;
+    char *buf = NULL;
+    buf = (char *) calloc(1, BUF_SIZE);
+    if (buf == NULL) {
+        ESP_LOGE(TAG, "calloc failed for size %d", BUF_SIZE);
+        goto exit;
+    }
+
+    ESP_LOGI(TAG, "Performing the SSL/TLS handshake...");
+
+    fflush(stdout);
+    while ((ret = mbedtls_ssl_handshake(ssl)) != 0) {
+        if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+            ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret);
+            goto exit;
+        }
+    }
+
+    ESP_LOGI(TAG, "Verifying peer X.509 certificate...");
+
+    if ((flags = mbedtls_ssl_get_verify_result(ssl)) != 0) {
+        /* In real life, we probably want to close connection if ret != 0 */
+        ESP_LOGW(TAG, "Failed to verify peer certificate!");
+        mbedtls_x509_crt_verify_info(buf, BUF_SIZE, "  ! ", flags);
+        ESP_LOGW(TAG, "verification info: %s", buf);
+    } else {
+        ESP_LOGI(TAG, "Certificate verified.");
+    }
+
+    ESP_LOGI(TAG, "Cipher suite is %s", mbedtls_ssl_get_ciphersuite(ssl));
+    ret = 0; /* No error */
+
+exit:
+    if (buf) {
+        free(buf);
+    }
+    return ret;
+}
+
+static void smtp_client_task(void *pvParameters)
+{
+    char *buf = NULL;
+    unsigned char base64_buffer[128];
+    int ret, len;
+    size_t base64_len;
+
+    mbedtls_entropy_context entropy;
+    mbedtls_ctr_drbg_context ctr_drbg;
+    mbedtls_ssl_context ssl;
+    mbedtls_x509_crt cacert;
+    mbedtls_ssl_config conf;
+    mbedtls_net_context server_fd;
+
+    mbedtls_ssl_init(&ssl);
+    mbedtls_x509_crt_init(&cacert);
+    mbedtls_ctr_drbg_init(&ctr_drbg);
+    ESP_LOGI(TAG, "Seeding the random number generator");
+
+    mbedtls_ssl_config_init(&conf);
+
+    mbedtls_entropy_init(&entropy);
+    if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+                                     NULL, 0)) != 0) {
+        ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned -0x%x", -ret);
+        goto exit;
+    }
+
+    ESP_LOGI(TAG, "Loading the CA root certificate...");
+
+    ret = mbedtls_x509_crt_parse(&cacert, server_root_cert_pem_start,
+                                 server_root_cert_pem_end - server_root_cert_pem_start);
+
+    if (ret < 0) {
+        ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x", -ret);
+        goto exit;
+    }
+
+    ESP_LOGI(TAG, "Setting hostname for TLS session...");
+
+    /* Hostname set here should match CN in server certificate */
+    if ((ret = mbedtls_ssl_set_hostname(&ssl, MAIL_SERVER)) != 0) {
+        ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned -0x%x", -ret);
+        goto exit;
+    }
+
+    ESP_LOGI(TAG, "Setting up the SSL/TLS structure...");
+
+    if ((ret = mbedtls_ssl_config_defaults(&conf,
+                                           MBEDTLS_SSL_IS_CLIENT,
+                                           MBEDTLS_SSL_TRANSPORT_STREAM,
+                                           MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
+        ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned -0x%x", -ret);
+        goto exit;
+    }
+
+    mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
+    mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
+    mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
+#ifdef CONFIG_MBEDTLS_DEBUG
+    mbedtls_esp_enable_debug_log(&conf, 4);
+#endif
+
+    if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
+        ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x", -ret);
+        goto exit;
+    }
+
+    mbedtls_net_init(&server_fd);
+
+    ESP_LOGI(TAG, "Connecting to %s:%s...", MAIL_SERVER, MAIL_PORT);
+
+    if ((ret = mbedtls_net_connect(&server_fd, MAIL_SERVER,
+                                   MAIL_PORT, MBEDTLS_NET_PROTO_TCP)) != 0) {
+        ESP_LOGE(TAG, "mbedtls_net_connect returned -0x%x", -ret);
+        goto exit;
+    }
+
+    ESP_LOGI(TAG, "Connected.");
+
+    mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
+
+    buf = (char *) calloc(1, BUF_SIZE);
+    if (buf == NULL) {
+        ESP_LOGE(TAG, "calloc failed for size %d", BUF_SIZE);
+        goto exit;
+    }
+#if SERVER_USES_STARTSSL
+    /* Get response */
+    ret = write_and_get_response(&server_fd, (unsigned char *) buf, 0);
+    VALIDATE_MBEDTLS_RETURN(ret, 200, 299, exit);
+
+    ESP_LOGI(TAG, "Writing EHLO to server...");
+    len = snprintf((char *) buf, BUF_SIZE, "EHLO %s\r\n", "ESP32");
+    ret = write_and_get_response(&server_fd, (unsigned char *) buf, len);
+    VALIDATE_MBEDTLS_RETURN(ret, 200, 299, exit);
+
+    ESP_LOGI(TAG, "Writing STARTTLS to server...");
+    len = snprintf((char *) buf, BUF_SIZE, "STARTTLS\r\n");
+    ret = write_and_get_response(&server_fd, (unsigned char *) buf, len);
+    VALIDATE_MBEDTLS_RETURN(ret, 200, 299, exit);
+
+    ret = perform_tls_handshake(&ssl);
+    if (ret != 0) {
+        goto exit;
+    }
+
+#else /* SERVER_USES_STARTSSL */
+    ret = perform_tls_handshake(&ssl);
+    if (ret != 0) {
+        goto exit;
+    }
+
+    /* Get response */
+    ret = write_ssl_and_get_response(&ssl, (unsigned char *) buf, 0);
+    VALIDATE_MBEDTLS_RETURN(ret, 200, 299, exit);
+    ESP_LOGI(TAG, "Writing EHLO to server...");
+
+    len = snprintf((char *) buf, BUF_SIZE, "EHLO %s\r\n", "ESP32");
+    ret = write_ssl_and_get_response(&ssl, (unsigned char *) buf, len);
+    VALIDATE_MBEDTLS_RETURN(ret, 200, 299, exit);
+
+#endif /* SERVER_USES_STARTSSL */
+
+    /* Authentication */
+    ESP_LOGI(TAG, "Authentication...");
+
+    ESP_LOGI(TAG, "Write AUTH LOGIN");
+    len = snprintf( (char *) buf, BUF_SIZE, "AUTH LOGIN\r\n" );
+    ret = write_ssl_and_get_response(&ssl, (unsigned char *) buf, len);
+    VALIDATE_MBEDTLS_RETURN(ret, 200, 399, exit);
+
+    ESP_LOGI(TAG, "Write USER NAME");
+    ret = mbedtls_base64_encode((unsigned char *) base64_buffer, sizeof(base64_buffer),
+                                &base64_len, (unsigned char *) SENDER_MAIL, strlen(SENDER_MAIL));
+    if (ret != 0) {
+        ESP_LOGE(TAG, "Error in mbedtls encode! ret = -0x%x", -ret);
+        goto exit;
+    }
+    len = snprintf((char *) buf, BUF_SIZE, "%s\r\n", base64_buffer);
+    ret = write_ssl_and_get_response(&ssl, (unsigned char *) buf, len);
+    VALIDATE_MBEDTLS_RETURN(ret, 300, 399, exit);
+
+    ESP_LOGI(TAG, "Write PASSWORD");
+    ret = mbedtls_base64_encode((unsigned char *) base64_buffer, sizeof(base64_buffer),
+                                &base64_len, (unsigned char *) SENDER_PASSWORD, strlen(SENDER_PASSWORD));
+    if (ret != 0) {
+        ESP_LOGE(TAG, "Error in mbedtls encode! ret = -0x%x", -ret);
+        goto exit;
+    }
+    len = snprintf((char *) buf, BUF_SIZE, "%s\r\n", base64_buffer);
+    ret = write_ssl_and_get_response(&ssl, (unsigned char *) buf, len);
+    VALIDATE_MBEDTLS_RETURN(ret, 200, 399, exit);
+
+    /* Compose email */
+    ESP_LOGI(TAG, "Write MAIL FROM");
+    len = snprintf((char *) buf, BUF_SIZE, "MAIL FROM:<%s>\r\n", SENDER_MAIL);
+    ret = write_ssl_and_get_response(&ssl, (unsigned char *) buf, len);
+    VALIDATE_MBEDTLS_RETURN(ret, 200, 299, exit);
+
+    ESP_LOGI(TAG, "Write RCPT");
+    len = snprintf((char *) buf, BUF_SIZE, "RCPT TO:<%s>\r\n", RECIPIENT_MAIL);
+    ret = write_ssl_and_get_response(&ssl, (unsigned char *) buf, len);
+    VALIDATE_MBEDTLS_RETURN(ret, 200, 299, exit);
+
+    ESP_LOGI(TAG, "Write DATA");
+    len = snprintf((char *) buf, BUF_SIZE, "DATA\r\n");
+    ret = write_ssl_and_get_response(&ssl, (unsigned char *) buf, len);
+    VALIDATE_MBEDTLS_RETURN(ret, 300, 399, exit);
+
+    ESP_LOGI(TAG, "Write Content");
+    /* We do not take action if message sending is partly failed. */
+    len = snprintf((char *) buf, BUF_SIZE,
+                   "From: %s\r\nSubject: mbed TLS Test mail\r\n"
+                   "To: %s\r\n"
+                   "MIME-Version: 1.0 (mime-construct 1.9)\n",
+                   "ESP32 SMTP Client", RECIPIENT_MAIL);
+
+    /**
+     * Note: We are not validating return for some ssl_writes.
+     * If by chance, it's failed; at worst email will be incomplete!
+     */
+    ret = write_ssl_data(&ssl, (unsigned char *) buf, len);
+
+    /* Multipart boundary */
+    len = snprintf((char *) buf, BUF_SIZE,
+                   "Content-Type: multipart/mixed;boundary=XYZabcd1234\n"
+                   "--XYZabcd1234\n");
+    ret = write_ssl_data(&ssl, (unsigned char *) buf, len);
+
+    /* Text */
+    len = snprintf((char *) buf, BUF_SIZE,
+                   "Content-Type: text/plain\n"
+                   "This is a simple test mail from the SMTP client example.\r\n"
+                   "\r\n"
+                   "Enjoy!\n\n--XYZabcd1234\n");
+    ret = write_ssl_data(&ssl, (unsigned char *) buf, len);
+
+    /* Attachment */
+    len = snprintf((char *) buf, BUF_SIZE,
+                   "Content-Type: image/image/png;name=esp_logo.png\n"
+                   "Content-Transfer-Encoding: base64\n"
+                   "Content-Disposition:attachment;filename=\"esp_logo.png\"\n");
+    ret = write_ssl_data(&ssl, (unsigned char *) buf, len);
+
+    /* Image contents... */
+    const uint8_t *offset = esp_logo_png_start;
+    while (offset < esp_logo_png_end - 1) {
+        int read_bytes = MIN(((sizeof (base64_buffer) - 1) / 4) * 3, esp_logo_png_end - offset - 1);
+        ret = mbedtls_base64_encode((unsigned char *) base64_buffer, sizeof(base64_buffer),
+                                    &base64_len, (unsigned char *) offset, read_bytes);
+        if (ret != 0) {
+            ESP_LOGE(TAG, "Error in mbedtls encode! ret = -0x%x", -ret);
+            goto exit;
+        }
+        offset += read_bytes;
+        len = snprintf((char *) buf, BUF_SIZE, "%s\r\n", base64_buffer);
+        ret = write_ssl_data(&ssl, (unsigned char *) buf, len);
+    }
+
+    len = snprintf((char *) buf, BUF_SIZE, "\n--XYZabcd1234\n");
+    ret = write_ssl_data(&ssl, (unsigned char *) buf, len);
+
+    len = snprintf((char *) buf, BUF_SIZE, "\r\n.\r\n");
+    ret = write_ssl_and_get_response(&ssl, (unsigned char *) buf, len);
+    VALIDATE_MBEDTLS_RETURN(ret, 200, 299, exit);
+    ESP_LOGI(TAG, "Email sent!");
+
+    /* Close connection */
+    mbedtls_ssl_close_notify(&ssl);
+    ret = 0; /* No errors */
+
+exit:
+    mbedtls_ssl_session_reset(&ssl);
+    mbedtls_net_free(&server_fd);
+
+    if (ret != 0) {
+        mbedtls_strerror(ret, buf, 100);
+        ESP_LOGE(TAG, "Last error was: -0x%x - %s", -ret, buf);
+    }
+
+    putchar('\n'); /* Just a new line */
+    if (buf) {
+        free(buf);
+    }
+    vTaskDelete(NULL);
+}
+
+void app_main()
+{
+    ESP_ERROR_CHECK(nvs_flash_init());
+    ESP_ERROR_CHECK(esp_netif_init());
+    ESP_ERROR_CHECK(esp_event_loop_create_default());
+
+    /**
+     * This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
+     * Read "Establishing Wi-Fi or Ethernet Connection" section in
+     * examples/protocols/README.md for more information about this function.
+     */
+    ESP_ERROR_CHECK(example_connect());
+    xTaskCreate(&smtp_client_task, "smtp_client_task", TASK_STACK_SIZE, NULL, 5, NULL);
+}