|
ProtoCore v0.0.1
Deterministic, zero-heap network stack for embedded targets
|
This example makes a tiny $5 computer (the ESP32) send you an email - for example, "the temperature is too high!" or "the door just opened." It is written so that a complete beginner can follow it. If you have never set up a mail server before, that is totally fine: we build one together, one step at a time.
Take your time. Nothing here can break your computer, and you can redo any step.
When you send an email, three things are involved:
The ESP32 talks to the mail server using a set of rules called SMTP (Simple Mail Transfer Protocol). SMTP is just a polite back-and-forth conversation: "Hello!" - "Hi!"
You do not need a Gmail account, a domain name, or any paid service. Everything here stays on your own network.
We will install Postfix on a Raspberry Pi (the steps are the same on any Debian/Ubuntu Linux; on macOS, Postfix is already installed - skip to step 4 and edit /etc/postfix/main.cf).
Step 1. Open a terminal on the Raspberry Pi. (On the Pi itself, or from another computer with ssh pi@<the-pi-ip>.) A "terminal" is the black window where you type commands.
Step 2. Install Postfix. Copy-paste this and press Enter:
sudo means "do this as the administrator" (it may ask for your password - type it; the characters stay invisible, that is normal).Step 3. Let the mail server listen to the network. By default Postfix only listens to itself. These three commands tell it to accept mail from your LAN:
postconf -e just edits Postfix's settings file for you. mynetworks is the list of addresses Postfix trusts - 192.168.0.0/16 means "every device on my home network."
Step 4. Restart Postfix so the changes take effect:
Step 5. Check it is listening. Run:
You should see a line containing 0.0.0.0:25. Port 25 is the standard "front door" for email. If you see it, your post office is open!
Step 6. Find the Pi's address and know your mailbox. Run hostname -I - the first number (e.g. 192.168.1.50) is the Pi's IP address; write it down. Your mailbox is your Linux username (for a Pi that is often pi); the ESP32 will send to <username>@<hostname> - for example pi@raspberrypi.local. You can see your username with whoami and the hostname with hostname.
Open SmtpAlert.ino and edit the lines marked CHANGE ME:
Only MAIL_SERVER and MAIL_TO really matter. MAIL_FROM can be anything.
Upload the sketch to the ESP32, then open the Serial Monitor at 115200 baud (in the Arduino IDE: Tools -> Serial Monitor). When the board restarts you should see:
If it says email sent, congratulations - your ESP32 just mailed you! 🎉
Back on the Raspberry Pi terminal, run:
or simply print the raw mailbox file:
You should see your message, "Hello from your ESP32."
The Serial Monitor prints email failed (SmtpResult N). Find N here:
| N | Name | What it means / how to fix |
|---|---|---|
| -2 | SMTP_ERR_CONNECT | The ESP32 could not reach the server. Two very common causes: (a) your WiFi router isolates wireless devices from each other ("AP/client isolation") so the ESP32 can't see your LAN server - turn that off, or use a server the ESP32 can reach; (b) your internet provider blocks outgoing port 25 (almost all do, to fight spam) - that only affects servers on the internet, not your own LAN Postfix, so a LAN server on port 25 is the easy path. For an internet provider, use encrypted submission instead (port 465 with tls = true, see "Going further"). Also double-check the MAIL_SERVER address. |
| -3 | SMTP_ERR_TLS | Only for encrypted mode. You set tls = true but the server does not do TLS on that port. Use port 25 with tls = false for a LAN Postfix. |
| -4 | SMTP_ERR_IO | The server went quiet. Confirm Postfix is running (sudo systemctl status postfix). |
| -5 | SMTP_ERR_PROTOCOL | The server refused a step. Usually the recipient is not local: make sure MAIL_TO's part after @ is a name your server owns (postconf mydestination lists them). |
| -6 | SMTP_ERR_AUTH | Wrong username/password (only when you set user/pass). |
| -1 | SMTP_ERR_ARG | A blank MAIL_SERVER, MAIL_FROM, or MAIL_TO. |
Still stuck? Watch the mail server's own log while the ESP32 tries: sudo tail -f /var/log/mail.log - it explains, in English, why it accepted or refused.
send_alert(...) call out of setup() and into your own code - e.g. inside an if (temperature > 30) check - so the board mails you only on a real event. Keep the messages short; this is for alerts, not newsletters.cfg.user and cfg.pass. The client uses AUTH LOGIN automatically.cfg.tls = true and cfg.port = 465, and build with TLS on: add -DPC_ENABLE_TLS=1 next to -DPC_ENABLE_SMTP=1. The whole conversation is then encrypted.MAIL_TO (e.g. 5551234567@txt.att.net for AT&T in the US - search the web for email to SMS gateway plus your carrier's name) and your email arrives as a text.SMTP lives inside the library, so the flag must reach the whole build:
(The Arduino IDE reads the flag from build_opt.h beside the sketch automatically.)
smtp_send() opens one TCP connection through the library's shared client transport (pc_client) and runs the RFC 5321 conversation: read the 220 greeting, say EHLO, optionally AUTH LOGIN (username/password base64-encoded), then MAIL FROM, RCPT TO, DATA, the message itself, and QUIT. The body is dot-stuffed (a line that begins with a . gets an extra .) so it can never accidentally end the message early, and the message finishes with the required <CR><LF>.<CR><LF>. There is no heap allocation - every buffer is a fixed compile-time size (PC_SMTP_*). The conversation logic (smtp_run) is separated from the network behind a tiny send/recv interface, which is why it can be fully unit-tested on a PC with a pretend server (see test/test_smtp).