前回に引き続きyahooメールのSSLメールをやってみました。
今回は設定系はiniファイルに持っていくことにしました。
変更しても再度コンパイルする必要がなくなりますからね。
m5stack-build.hatenablog.com
サンプルコード(mail.ino)
#include <M5Core2.h>
#include <WiFi.h>
#include "Mailer.h"
const char* subject = "From M5stack";
const char* content = "Hello, this is M5stack Core2.";
void setup() {
String config_ini;
String ssid;
String password;
String mail_username;
String mail_pass;
String mail_from_address;
String mail_to_address;
String smtp_server;
String smtp_port;
unsigned short ausIdx = 0;
M5.begin();
SD.begin();
Serial.begin(115200);
delay(10);
M5.Lcd.setTextSize(1);
File datFile = SD.open("/set/config.ini");
if( datFile )
{
M5.Lcd.println("File open successful");
Serial.println("File open successful");
while( datFile.available() )
{
config_ini = config_ini + datFile.readString();
}
datFile.close();
}
else
{
M5.Lcd.println("File open error hello.txt");
}
config_ini = config_ini.substring(config_ini.indexOf("#SSID\r\n") + 7);
ssid = config_ini.substring(0, config_ini.indexOf("\r\n"));
config_ini = config_ini.substring(config_ini.indexOf("#SSID_PASS\r\n") + 12);
password = config_ini.substring(0, config_ini.indexOf("\r\n"));
M5.Lcd.print("Connecting to YOUR_SSID ");
Serial.println("Connecting to YOUR_SSID ");
WiFi.begin(ssid.c_str(), password.c_str());
while (WiFi.status() != WL_CONNECTED) {
delay(500);
M5.Lcd.print(".");
}
M5.Lcd.println(" CONNECTED");
Serial.println(" CONNECTED");
config_ini = config_ini.substring(config_ini.indexOf("#MAIL_USERNAME\r\n") + 16);
mail_username = config_ini.substring(0, config_ini.indexOf("\r\n"));
config_ini = config_ini.substring(config_ini.indexOf("#MAIL_PASS\r\n") + 12);
mail_pass = config_ini.substring(0, config_ini.indexOf("\r\n"));
config_ini = config_ini.substring(config_ini.indexOf("#MAIL_FROM_ADDR\r\n") + 17);
mail_from_address = config_ini.substring(0, config_ini.indexOf("\r\n"));
config_ini = config_ini.substring(config_ini.indexOf("#MAIL_TO_ADDR\r\n") + 15);
mail_to_address = config_ini.substring(0, config_ini.indexOf("\r\n"));
config_ini = config_ini.substring(config_ini.indexOf("#SMTP_PORT\r\n") + 12);
smtp_port = config_ini.substring(0, config_ini.indexOf("\r\n"));
config_ini = config_ini.substring(config_ini.indexOf("#SMTP_SERVER\r\n") + 14);
smtp_server = config_ini.substring(0, config_ini.indexOf("\r\n"));
Mailer mail(mail_username.c_str(), mail_pass.c_str(), mail_from_address.c_str(), atoi(smtp_port.c_str()), smtp_server.c_str());
mail.send(mail_to_address.c_str(), subject, content);
}
void loop() {
delay(10000);
}
iniファイルに格納して読みだす方法は昔の記事ですが参考までに。。
m5stack-build.hatenablog.com
サンプルコード(Mailer.h)
2022/06/19 追記
証明書もファイルから読み出すように変更した。
#pragma once
#include <ssl_client.h>
#include <WiFiClientSecure.h>
#include <base64.h>
class Mailer {
public:
Mailer(const char* username, const char* password, const char* from_address, const int smtp_port, const char* smtp_hostname):
username(username), password(password), from_address(from_address), smtp_port(smtp_port), smtp_hostname(smtp_hostname) {}
bool send(const String& to_address, const String& subject, const String& content) {
WiFiClientSecure client;
String root_ca;
File datFile = SD.open("/set/yahoo_root.cer");
if( datFile )
{
M5.Lcd.println("Root File open successful");
Serial.println("Root File open successful");
while( datFile.available() )
{
root_ca = root_ca + datFile.readString();
}
datFile.close();
}
else
{
M5.Lcd.println("Root File open error");
}
client.setCACert(root_ca.c_str());
M5.Lcd.printf("Connecting to %s\n", smtp_hostname);
Serial.printf("Connecting to %s\n", smtp_hostname);
if (!client.connect(smtp_hostname, smtp_port)) {
Serial.println("Could not connect to mail server");
return false;
}
if (!readResponse(client, "220")) {
Serial.println("Connection Error");
return false;
}
client.println("HELO friend");
if (!readResponse(client, "250")) {
Serial.println("identification error");
return false;
}
client.println("AUTH LOGIN");
if (!readResponse(client, "334")) {
Serial.println("AUTH LOGIN failed");
return false;
}
client.println(base64::encode(username));
if (!readResponse(client, "334")) {
Serial.println("AUTH LOGIN failed");
return false;
}
client.println(base64::encode(password));
if (!readResponse(client, "235")) {
Serial.println("SMTP AUTH error");
return false;
}
client.println("MAIL FROM: <" + String(from_address) + '>');
if (!readResponse(client, "250")) {
Serial.println("MAIL FROM failed");
return false;
}
client.println("RCPT TO: <" + to_address + '>');
if (!readResponse(client, "250")) {
Serial.println("RCPT TO failed");
return false;
}
client.println("DATA");
if (!readResponse(client, "354")) {
Serial.println("SMTP DATA error");
return false;
}
client.println("From: <" + String(from_address) + ">");
delay(100);
client.println("To: <" + to_address + ">");
delay(100);
client.println("Subject: " + subject);
delay(100);
client.println("Mime-Version: 1.0");
delay(100);
client.println("Content-Type: text/html");
delay(100);
client.println();
delay(100);
client.println(content);
delay(100);
client.println(".");
if (!readResponse(client, "250")) {
Serial.println("Sending message error");
return false;
}
client.println("QUIT");
if (!readResponse(client, "221")) {
Serial.println("QUIT failed");
return false;
}
M5.Lcd.println("Sending E-mail Successful");
Serial.println("Sending E-mail Successful");
return true;
}
private:
const char* username;
const char* password;
const char* from_address;
const int smtp_port;
const char* smtp_hostname;
bool readResponse(WiFiClientSecure &client, const String &target, uint32_t timeout_ms = 10000) {
uint32_t timeStamp = millis();
while (1) {
if (client.available()) break;
if (millis() > timeStamp + timeout_ms) {
Serial.println("SMTP Response TIMEOUT!");
return false;
}
delay(1);
}
String res = client.readStringUntil('\n');
res.trim();
Serial.printf("Response: %s\n", res.c_str());
if (target != "" && res.indexOf(target) == -1) return false;
return true;
}
};