Raspberry Pi Pico W: отправка электронной почты через SMTP-сервер (MicroPython)

Узнайте, как отправлять электронные письма с Raspberry Pi Pico, используя SMTP-сервер. Эта функция может быть полезна в ваших проектах автоматизации и IoT для отправки уведомлений, сообщений с показаниями датчиков и многого другого. Мы будем программировать Raspberry Pi Pico с использованием прошивки MicroPython.

Raspberry Pi Pico W отправка электронной почты через SMTP-сервер MicroPython

Впервые работаете с Raspberry Pi Pico? Начните знакомство с Raspberry Pi Pico здесь.

Предварительные требования – прошивка MicroPython

Для выполнения этого руководства вам необходимо установить прошивку MicroPython на плату Raspberry Pi Pico. Вам также понадобится IDE для написания и загрузки кода на плату.

Рекомендуемая IDE для MicroPython на Raspberry Pi Pico – это Thonny IDE. Следуйте следующему руководству, чтобы узнать, как установить Thonny IDE, прошить MicroPython и загрузить код на плату.

Знакомство с SMTP-серверами

SMTP означает Simple Mail Transfer Protocol (простой протокол передачи почты) и является интернет-стандартом для передачи электронной почты. Для отправки электронных писем с помощью Raspberry Pi Pico вам необходимо подключить его к SMTP-серверу.

Модуль uMail

Для удобной отправки электронных писем с MicroPython мы будем использовать модуль uMail. Этот модуль не входит в стандартную коллекцию библиотек MicroPython, поэтому нам нужно будет загрузить его отдельно на нашу плату – инструкции по этому поводу мы предоставим позже в руководстве.

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

Для отправки электронных писем с Raspberry Pi Pico вам нужна электронная почта отправителя, и вам необходимо знать настройки SMTP-сервера вашей почты. Ниже вы найдёте настройки для наиболее популярных почтовых провайдеров.

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

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

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

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

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

  • Порт SMTP (TLS): 587

  • Порт SMTP (SSL): 465

  • Требуется SMTP TLS/SSL: да

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

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

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

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

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

  • Порт SMTP: 587

  • Требуется SMTP TLS/SSL: Да

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

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

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

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

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

  • Порт SMTP: 587

  • Требуется SMTP TLS/SSL: Да

Если вы используете другого почтового провайдера, вам нужно найти его настройки SMTP-сервера – вы легко найдёте их с помощью быстрого поиска в Google.

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

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

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

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

Создайте новый аккаунт электронной почты для отправки писем с Raspberry Pi Pico. Если вы хотите использовать аккаунт Gmail, перейдите по этой ссылке, чтобы создать новый.

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

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

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

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

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

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

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

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

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

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

  2. В строке поиска найдите Пароль приложения (App Password).

  3. Нажмите на меню Пароли приложений.

Gmail - меню создания пароля приложения
  1. Теперь вы можете создать новый пароль приложения для использования с Raspberry Pi Pico. Дайте ему имя. Например: Pi Pico.

Gmail - создание нового пароля приложения для RPi Pico

Нажмите Создать. Ваш пароль приложения будет отображён. Скопируйте его в безопасное место, потому что он вам понадобится позже (даже если написано, что вам это не нужно).

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

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

Пароль приложения создан для Raspberry Pi Pico Gmail

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

Загрузка модуля uMail

Для отправки писем мы будем использовать модуль uMail. Вы можете ознакомиться с его страницей на Github и несколькими примерами. Эта библиотека не входит в стандартную библиотеку MicroPython по умолчанию. Поэтому вам нужно загрузить следующий файл на Raspberry Pi Pico (сохраните его под именем umail.py), прежде чем использовать библиотеку.

# uMail (MicroMail) for MicroPython Copyright (c) 2018 Shawwwn <shawwwn1@gmai.com> https://github.com/shawwwn/uMail/blob/master/umail.py License: MIT
import usocket

DEFAULT_TIMEOUT = 10 # sec
LOCAL_DOMAIN = '127.0.0.1'
CMD_EHLO = 'EHLO'
CMD_STARTTLS = 'STARTTLS'
CMD_AUTH = 'AUTH'
CMD_MAIL = 'MAIL'
AUTH_PLAIN = 'PLAIN'
AUTH_LOGIN = 'LOGIN'

class SMTP:
    def cmd(self, cmd_str):
        sock = self._sock;
        sock.write('%s\r\n' % cmd_str)
        resp = []
        next = True
        while next:
            code = sock.read(3)
            next = sock.read(1) == b'-'
            resp.append(sock.readline().strip().decode())
        return int(code), resp

    def __init__(self, host, port, ssl=False, username=None, password=None):
        import ssl
        self.username = username
        addr = usocket.getaddrinfo(host, port)[0][-1]
        sock = usocket.socket(usocket.AF_INET, usocket.SOCK_STREAM)
        sock.settimeout(DEFAULT_TIMEOUT)
        sock.connect(addr)
        if ssl:
            sock = ssl.wrap_socket(sock)
        code = int(sock.read(3))
        sock.readline()
        assert code==220, 'cant connect to server %d, %s' % (code, resp)
        self._sock = sock

        code, resp = self.cmd(CMD_EHLO + ' ' + LOCAL_DOMAIN)
        assert code==250, '%d' % code
        if not ssl and CMD_STARTTLS in resp:
            code, resp = self.cmd(CMD_STARTTLS)
            assert code==220, 'start tls failed %d, %s' % (code, resp)
            self._sock = ssl.wrap_socket(sock)

        if username and password:
            self.login(username, password)

    def login(self, username, password):
        self.username = username
        code, resp = self.cmd(CMD_EHLO + ' ' + LOCAL_DOMAIN)
        assert code==250, '%d, %s' % (code, resp)

        auths = None
        for feature in resp:
            if feature[:4].upper() == CMD_AUTH:
                auths = feature[4:].strip('=').upper().split()
        assert auths!=None, "no auth method"

        from ubinascii import b2a_base64 as b64
        if AUTH_PLAIN in auths:
            cren = b64("\0%s\0%s" % (username, password))[:-1].decode()
            code, resp = self.cmd('%s %s %s' % (CMD_AUTH, AUTH_PLAIN, cren))
        elif AUTH_LOGIN in auths:
            code, resp = self.cmd("%s %s %s" % (CMD_AUTH, AUTH_LOGIN, b64(username)[:-1].decode()))
            assert code==334, 'wrong username %d, %s' % (code, resp)
            code, resp = self.cmd(b64(password)[:-1].decode())
        else:
            raise Exception("auth(%s) not supported " % ', '.join(auths))

        assert code==235 or code==503, 'auth error %d, %s' % (code, resp)
        return code, resp

    def to(self, addrs, mail_from=None):
        mail_from = self.username if mail_from==None else mail_from
        code, resp = self.cmd(CMD_EHLO + ' ' + LOCAL_DOMAIN)
        assert code==250, '%d' % code
        code, resp = self.cmd('MAIL FROM: <%s>' % mail_from)
        assert code==250, 'sender refused %d, %s' % (code, resp)

        if isinstance(addrs, str):
            addrs = [addrs]
        count = 0
        for addr in addrs:
            code, resp = self.cmd('RCPT TO: <%s>' % addr)
            if code!=250 and code!=251:
                print('%s refused, %s' % (addr, resp))
                count += 1
        assert count!=len(addrs), 'recipient refused, %d, %s' % (code, resp)

        code, resp = self.cmd('DATA')
        assert code==354, 'data refused, %d, %s' % (code, resp)
        return code, resp

    def write(self, content):
        self._sock.write(content)

    def send(self, content=''):
        if content:
            self.write(content)
        self._sock.write('\r\n.\r\n') # the five letter sequence marked for ending
        line = self._sock.readline()
        return (int(line[:3]), line[4:].strip().decode())

    def quit(self):
        self.cmd("QUIT")
        self._sock.close()

Посмотреть исходный код

  1. Создайте новый файл в Thonny IDE и вставьте предыдущий код;

  2. Перейдите в File > Save as… и выберите Raspberry Pi Pico;

  3. Сохраните файл с именем umail.py (не меняйте имя).

На этом этапе библиотека должна быть успешно загружена на вашу плату. Теперь вы можете использовать функции библиотеки в своём коде, импортировав библиотеку: import umail.

Отправка писем с Raspberry Pi Pico (MicroPython) – код

Следующий MicroPython-скрипт отправляет простое электронное письмо при первой загрузке/перезагрузке платы Raspberry Pi Pico.

# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-w-send-email-micropython/
# Micropython lib to send emails: https://github.com/shawwwn/uMail
import umail
import network
import time

# Your network credentials
ssid = 'REPLACE_WITH_YOUR_SSID'
password = 'REPLACE_WITH_YOUR_PASSWORD'

# Email details
sender_email = 'REPLACE_WITH_THE_SENDER_EMAIL'
sender_name = 'Raspberry Pi Pico'
sender_app_password = 'REPLACE_WITH_THE_SENDER_EMAIL_APP_PASSWORD'
recipient_email ='REPLACE_WITH_THE_RECIPIENT_EMAIL'
email_subject ='Hello from RPi Pico W'

# Init Wi-Fi Interface
def init_wifi(ssid, password):
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    # Connect to your network
    wlan.connect(ssid, password)
    # Wait for Wi-Fi connection
    connection_timeout = 10
    while connection_timeout > 0:
        print(wlan.status())
        if wlan.status() >= 3:
            break
        connection_timeout -= 1
        print('Waiting for Wi-Fi connection...')
        time.sleep(1)
    # Check if connection is successful
    if wlan.status() != 3:
        print('Failed to connect to Wi-Fi')
        return False
    else:
        print('Connection successful!')
        network_info = wlan.ifconfig()
        print('IP address:', network_info[0])
        return True

# Connect to your network
init_wifi(ssid, password)

# Send the email
smtp = umail.SMTP('smtp.gmail.com', 465, ssl=True) # Gmail's SSL port

try:
    smtp.login(sender_email, sender_app_password)
    smtp.to(recipient_email)
    smtp.write("From:" + sender_name + "<"+ sender_email+">\n")
    smtp.write("Subject:" + email_subject + "\n")
    smtp.write("Hello from the Raspberry Pi Pico. Testing.")
    smtp.send()
    print("Email Sent Successfully")

except Exception as e:
    print("Failed to send email:", e)
finally:
    smtp.quit()

Посмотреть исходный код

Вам нужно вставить свои данные в код перед загрузкой на плату: SSID и пароль, электронную почту отправителя, имя отправителя и соответствующий пароль приложения (это именно пароль приложения, а не пароль электронной почты), электронную почту получателя и тему письма.

После ввода всех данных вы можете запустить код для тестирования. Если вы хотите, чтобы код работал без подключения к компьютеру, вам нужно сохранить его на Raspberry Pi Pico под именем main.py.

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

Сначала подключите необходимые библиотеки. Библиотеку umail, которую мы загрузили ранее на Pico, чтобы мы могли отправлять электронные письма, и библиотеку network, чтобы настроить Pico как Wi-Fi-станцию для подключения к интернету (локальной сети).

import umail
import network

Вставьте учётные данные вашей сети, SSID и пароль, в следующие переменные, чтобы ваша плата могла подключиться к интернету:

ssid = 'REPLACE_WITH_YOUR_SSID'
password = 'REPLACE_WITH_YOUR_PASSWORD'

Вставьте данные электронной почты: адрес отправителя, имя отправителя и соответствующий пароль приложения. Вам нужно создать пароль приложения – обычный пароль электронной почты не будет работать, смотрите раздел Создание пароля приложения.

# Email details
sender_email = 'REPLACE_WITH_THE_SENDER_EMAIL'
sender_name = 'Raspberry Pi Pico'
sender_app_password = 'REPLACE_WITH_THE_SENDER_EMAIL_APP_PASSWORD'

Вставьте электронную почту получателя в переменную recipient_email:

recipient_email ='REPLACE_WITH_THE_RECIPIENT_EMAIL'

Тема письма установлена на Hello from RPi Pico W, но вы можете изменить её в переменной email_subject.

email_subject ='Hello from RPi Pico W'

Мы создали функцию init_wifi(), которая принимает в качестве аргументов SSID и пароль сети, к которой вы хотите подключиться. Вы должны вызвать эту функцию позже, чтобы подключить плату Pico к интернету.

# Init Wi-Fi Interface
def init_wifi(ssid, password):
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    # Connect to your network
    wlan.connect(ssid, password)
    # Wait for Wi-Fi connection
    connection_timeout = 10
    while connection_timeout > 0:
        print(wlan.status())
        if wlan.status() >= 3:
            break
        connection_timeout -= 1
        print('Waiting for Wi-Fi connection...')
        time.sleep(1)
    # Check if connection is successful
    if wlan.status() != 3:
        print('Failed to connect to Wi-Fi')
        return False
    else:
        print('Connection successful!')
        network_info = wlan.ifconfig()
        print('IP address:', network_info[0])
        return True

Перед отправкой электронного письма нам нужно подключить Raspberry Pi Pico к интернету, поэтому вызовите функцию init_wifi() (передайте в качестве аргументов ssid и password).

# Connect to your network
init_wifi(ssid, password)

Теперь мы наконец можем начать подготовку и отправку электронного письма.

Начните с создания SMTP-клиента, используя настройки SMTP вашего почтового провайдера, с именем smtp. Здесь мы используем аккаунт Gmail. Измените настройки, если вы используете другого почтового провайдера – укажите сервер, порт и требуется ли SSL или нет.

smtp = umail.SMTP('smtp.gmail.com', 465, ssl=True) # Gmail's SSL port

Далее у нас есть операторы try и except для отправки письма или вывода сообщения об ошибке в случае неудачи.

Затем войдите в свой аккаунт с помощью метода login() на клиенте smtp – передайте в качестве аргументов электронную почту и соответствующий пароль приложения.

smtp.login(sender_email, sender_app_password)

Установите получателя с помощью метода to() и передайте электронную почту получателя в качестве аргумента:

smtp.to(recipient_email)

Затем используйте метод write() для написания письма. Вы можете использовать этот метод следующим образом для установки имени отправителя.

smtp.write("From:" + sender_name + "<"+ sender_email+">\n")

Вы можете использовать следующую строку для установки темы письма.

smtp.write("Subject:" + email_subject + "\n")

Наконец, вы можете написать содержимое вашего письма. Это просто тестовое письмо. Мы устанавливаем сообщение «Hello from the Raspberry Pi Pico. Testing.». Метод write() отправляет письмо на SMTP-сервер.

smtp.write("Hello from the Raspberry Pi Pico. Testing.")

Если вам нужно отправить длинную строку в качестве тела письма, разбейте сообщение на более мелкие части и отправьте каждую часть с помощью метода write()смотрите документацию библиотеки uMail.

Наконец, используйте метод send() для того, чтобы SMTP-сервер отправил письмо получателю.

smtp.send()

Если отправка письма не удалась, будет выведено сообщение об ошибке:

except Exception as e:
    print("Failed to send email:", e)

В конце закройте соединение с сервером с помощью метода quit().

finally:
    smtp.quit()

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

После загрузки модуля umail.py вы можете запустить наш пример кода для тестирования отправки электронного письма.

Запуск MicroPython-скрипта в Thonny IDE

Pico должен подключиться к интернету и отправить электронное письмо.

Raspberry Pi Pico - электронное письмо успешно отправлено

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

Тестовое письмо, отправленное с Raspberry Pi Pico с помощью MicroPython (входящие)

Откройте письмо, чтобы проверить его содержимое.

Тестовое письмо, отправленное с Raspberry Pi Pico с помощью MicroPython

Заключение

В этом руководстве вы узнали, как отправлять электронные письма с Raspberry Pi Pico W с помощью MicroPython. Отправка электронного письма через SMTP-сервер очень проста благодаря модулю uMail для MicroPython.

Мы показали вам простой пример отправки электронных писем. Теперь вы можете использовать это в своих проектах для отправки уведомлений, показаний датчиков и других приложений.

Надеемся, что это руководство было для вас полезным.