mirror of https://github.com/arendst/Tasmota.git
666 lines
14 KiB
C++
666 lines
14 KiB
C++
#ifdef USE_SENDMAIL
|
|
|
|
#ifndef USE_ESP32MAIL
|
|
|
|
#include "sendemail.h"
|
|
|
|
// enable serial debugging
|
|
//#define DEBUG_EMAIL_PORT
|
|
|
|
// sendmail works only with server port 465 SSL and doesnt support STARTTLS (not supported in Arduino)
|
|
// only a couple of mailservers support this (e.g. gmail,gmx,yahoo,freenetmail)
|
|
// sendmail [server:port:user:passwd:from:to:subject] body
|
|
// sendmail [*:*:*:*:*:to:subject] data uses defines from user_config_overwrite
|
|
// #define EMAIL_USER "user"
|
|
// #define EMAIL_PASSWORD "passwd"
|
|
// #define EMAIL_FROM "<mr.x@gmail.com>"
|
|
// #define EMAIL_SERVER "smtp.gmail.com"
|
|
// #define EMAIL_PORT 465
|
|
// if email body consist of a single * and scripter is present
|
|
// and a section >m is found, the lines in this section (until #) are sent
|
|
// as email body
|
|
|
|
// sendmail works with pre2.6 using Light BearSSL
|
|
//HW Watchdog 8.44 sec.
|
|
//SW Watchdog 3.2 sec.
|
|
|
|
#ifndef SEND_MAIL_MINRAM
|
|
#define SEND_MAIL_MINRAM 12*1024
|
|
#endif
|
|
|
|
void script_send_email_body(void(*func)(char *));
|
|
|
|
#define xPSTR(a) a
|
|
|
|
uint16_t SendMail(char *buffer) {
|
|
char *params,*oparams;
|
|
const char *mserv;
|
|
uint16_t port;
|
|
const char *user;
|
|
const char *pstr;
|
|
const char *passwd;
|
|
const char *from;
|
|
const char *to;
|
|
const char *subject;
|
|
const char *cmd;
|
|
char auth=0;
|
|
uint16_t status=1;
|
|
SendEmail *mail=0;
|
|
uint16_t blen;
|
|
char *endcmd;
|
|
|
|
|
|
// return if not enough memory
|
|
uint16_t mem=ESP.getFreeHeap();
|
|
if (mem<SEND_MAIL_MINRAM) {
|
|
return 4;
|
|
}
|
|
|
|
while (*buffer==' ') buffer++;
|
|
|
|
if (*buffer!='[') {
|
|
goto exit;
|
|
}
|
|
|
|
buffer++;
|
|
|
|
endcmd=strchr(buffer,']');
|
|
if (!endcmd) {
|
|
goto exit;
|
|
}
|
|
|
|
// copy params
|
|
blen=(uint32_t)endcmd-(uint32_t)buffer;
|
|
oparams=(char*)calloc(blen+2,1);
|
|
if (!oparams) return 4;
|
|
params=oparams;
|
|
strncpy(oparams,buffer,blen+2);
|
|
oparams[blen]=0;
|
|
|
|
cmd=endcmd+1;
|
|
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("mailsize: %d"),blen);
|
|
#endif
|
|
|
|
mserv=strtok(params,":");
|
|
if (!mserv) {
|
|
goto exit;
|
|
}
|
|
|
|
// port
|
|
pstr=strtok(NULL,":");
|
|
if (!pstr) {
|
|
goto exit;
|
|
}
|
|
|
|
#ifdef EMAIL_PORT
|
|
if (*pstr=='*') {
|
|
port=EMAIL_PORT;
|
|
} else {
|
|
port=atoi(pstr);
|
|
}
|
|
#else
|
|
port=atoi(pstr);
|
|
#endif
|
|
|
|
user=strtok(NULL,":");
|
|
if (!user) {
|
|
goto exit;
|
|
}
|
|
|
|
passwd=strtok(NULL,":");
|
|
if (!passwd) {
|
|
goto exit;
|
|
}
|
|
|
|
from=strtok(NULL,":");
|
|
if (!from) {
|
|
goto exit;
|
|
}
|
|
|
|
to=strtok(NULL,":");
|
|
if (!to) {
|
|
goto exit;
|
|
}
|
|
|
|
subject=strtok(NULL,"]");
|
|
if (!subject) {
|
|
goto exit;
|
|
}
|
|
|
|
|
|
#ifdef EMAIL_USER
|
|
if (*user=='*') {
|
|
user=xPSTR(EMAIL_USER);
|
|
}
|
|
#endif
|
|
#ifdef EMAIL_PASSWORD
|
|
if (*passwd=='*') {
|
|
passwd=xPSTR(EMAIL_PASSWORD);
|
|
}
|
|
#endif
|
|
#ifdef EMAIL_SERVER
|
|
if (*mserv=='*') {
|
|
mserv=xPSTR(EMAIL_SERVER);
|
|
}
|
|
#endif //USE_SENDMAIL
|
|
|
|
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s - %d - %s - %s"),mserv,port,user,passwd);
|
|
#endif
|
|
|
|
// 2 seconds timeout
|
|
#ifndef MAIL_TIMEOUT
|
|
#define MAIL_TIMEOUT 2000
|
|
#endif
|
|
mail = new SendEmail(mserv,port,user,passwd, MAIL_TIMEOUT, auth);
|
|
|
|
#ifdef EMAIL_FROM
|
|
if (*from=='*') {
|
|
from=xPSTR(EMAIL_FROM);
|
|
}
|
|
#endif
|
|
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s - %s - %s - %s"),from,to,subject,cmd);
|
|
#endif
|
|
|
|
if (mail) {
|
|
bool result=mail->send(from,to,subject,cmd);
|
|
delete mail;
|
|
if (result==true) status=0;
|
|
}
|
|
|
|
exit:
|
|
if (oparams) free(oparams);
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
#ifdef ESP8266
|
|
WiFiClient *g_client;
|
|
SendEmail::SendEmail(const String& host, const int port, const String& user, const String& passwd, const int timeout, const int auth_used) :
|
|
host(host), port(port), user(user), passwd(passwd), timeout(timeout), ssl(ssl), auth_used(auth_used), client(new BearSSL::WiFiClientSecure_light(1024,1024)) {
|
|
}
|
|
#else
|
|
WiFiClient *g_client;
|
|
SendEmail::SendEmail(const String& host, const int port, const String& user, const String& passwd, const int timeout, const int auth_used) :
|
|
host(host), port(port), user(user), passwd(passwd), timeout(timeout), ssl(ssl), auth_used(auth_used), client(new WiFiClientSecure()) {
|
|
}
|
|
#endif
|
|
|
|
String SendEmail::readClient() {
|
|
delay(0);
|
|
String r = client->readStringUntil('\n');
|
|
|
|
r.trim();
|
|
while (client->available()) {
|
|
delay(0);
|
|
r += client->readString();
|
|
}
|
|
return r;
|
|
}
|
|
|
|
bool SendEmail::send(const String& from, const String& to, const String& subject, const char *msg) {
|
|
bool status=false;
|
|
String buffer;
|
|
|
|
if (!host.length()) {
|
|
return status;
|
|
}
|
|
|
|
client->setTimeout(timeout);
|
|
// smtp connect
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("Connecting: %s on port %d"),host.c_str(),port);
|
|
#endif
|
|
|
|
if (!client->connect(host.c_str(), port)) {
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P(LOG_LEVEL_INFO, PSTR("Connection failed"));
|
|
#endif
|
|
goto exit;
|
|
}
|
|
|
|
buffer = readClient();
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
if (!buffer.startsWith(F("220"))) {
|
|
goto exit;
|
|
}
|
|
|
|
buffer = F("EHLO ");
|
|
buffer += client->localIP().toString();
|
|
|
|
client->println(buffer);
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
buffer = readClient();
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
if (!buffer.startsWith(F("250"))) {
|
|
goto exit;
|
|
}
|
|
if (user.length()>0 && passwd.length()>0 ) {
|
|
|
|
buffer = F("AUTH LOGIN");
|
|
client->println(buffer);
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
buffer = readClient();
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
if (!buffer.startsWith(F("334")))
|
|
{
|
|
goto exit;
|
|
}
|
|
base64 b;
|
|
buffer = b.encode(user);
|
|
|
|
client->println(buffer);
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
buffer = readClient();
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
if (!buffer.startsWith(F("334"))) {
|
|
goto exit;
|
|
}
|
|
buffer = b.encode(passwd);
|
|
client->println(buffer);
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
buffer = readClient();
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
if (!buffer.startsWith(F("235"))) {
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// smtp send mail
|
|
buffer = F("MAIL FROM:");
|
|
buffer += from;
|
|
client->println(buffer);
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
buffer = readClient();
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
if (!buffer.startsWith(F("250"))) {
|
|
goto exit;
|
|
}
|
|
buffer = F("RCPT TO:");
|
|
buffer += to;
|
|
client->println(buffer);
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
buffer = readClient();
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
if (!buffer.startsWith(F("250"))) {
|
|
goto exit;
|
|
}
|
|
|
|
buffer = F("DATA");
|
|
client->println(buffer);
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
buffer = readClient();
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
if (!buffer.startsWith(F("354"))) {
|
|
goto exit;
|
|
}
|
|
buffer = F("From: ");
|
|
buffer += from;
|
|
client->println(buffer);
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
buffer = F("To: ");
|
|
buffer += to;
|
|
client->println(buffer);
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
buffer = F("Subject: ");
|
|
buffer += subject;
|
|
buffer += F("\r\n");
|
|
client->println(buffer);
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
|
|
#ifdef USE_SCRIPT
|
|
if (*msg=='*' && *(msg+1)==0) {
|
|
g_client=client;
|
|
script_send_email_body(xsend_message_txt);
|
|
} else {
|
|
client->println(msg);
|
|
}
|
|
#else
|
|
client->println(msg);
|
|
#endif
|
|
client->println('.');
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
|
|
buffer = F("QUIT");
|
|
client->println(buffer);
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
|
|
#endif
|
|
|
|
status=true;
|
|
exit:
|
|
|
|
return status;
|
|
}
|
|
|
|
void xsend_message_txt(char *msg) {
|
|
g_client->println(msg);
|
|
}
|
|
#else
|
|
|
|
/*
|
|
* Created by K. Suwatchai (Mobizt)
|
|
*
|
|
* Email: k_suwatchai@hotmail.com
|
|
*
|
|
* Github: https://github.com/mobizt
|
|
*
|
|
* Copyright (c) 2019 mobizt
|
|
*
|
|
*/
|
|
|
|
|
|
//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
|
|
|
|
//To receive Email for Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
|
|
|
|
#include "ESP32_MailClient.h"
|
|
#include "SD.h"
|
|
|
|
//For demo only
|
|
//#include "image.h"
|
|
|
|
#ifndef SEND_MAIL32_MINRAM
|
|
#define SEND_MAIL32_MINRAM 30*1024
|
|
#endif
|
|
|
|
void script_send_email_body(void(*func)(char *));
|
|
|
|
#define xPSTR(a) a
|
|
//The Email Sending data object contains config and data to send
|
|
SMTPData smtpData;
|
|
|
|
//Callback function to get the Email sending status
|
|
//void sendCallback(SendStatus info);
|
|
//#define DEBUG_EMAIL_PORT
|
|
|
|
uint16_t SendMail(char *buffer) {
|
|
char *params,*oparams;
|
|
const char *mserv;
|
|
uint16_t port;
|
|
const char *user;
|
|
const char *pstr;
|
|
const char *passwd;
|
|
const char *from;
|
|
const char *to;
|
|
const char *subject;
|
|
const char *cmd;
|
|
uint16_t status=1;
|
|
uint16_t blen;
|
|
char *endcmd;
|
|
|
|
// return if not enough memory
|
|
uint32_t mem=ESP.getFreeHeap();
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("heap: %d"),mem);
|
|
if (mem<SEND_MAIL32_MINRAM) {
|
|
return 4;
|
|
}
|
|
|
|
while (*buffer==' ') buffer++;
|
|
|
|
if (*buffer!='[') {
|
|
goto exit;
|
|
}
|
|
|
|
buffer++;
|
|
|
|
endcmd=strchr(buffer,']');
|
|
if (!endcmd) {
|
|
goto exit;
|
|
}
|
|
|
|
// copy params
|
|
blen=(uint32_t)endcmd-(uint32_t)buffer;
|
|
oparams=(char*)calloc(blen+2,1);
|
|
if (!oparams) return 4;
|
|
params=oparams;
|
|
strncpy(oparams,buffer,blen+2);
|
|
oparams[blen]=0;
|
|
|
|
cmd=endcmd+1;
|
|
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("mailsize: %d"),blen);
|
|
#endif
|
|
|
|
mserv=strtok(params,":");
|
|
if (!mserv) {
|
|
goto exit;
|
|
}
|
|
|
|
// port
|
|
pstr=strtok(NULL,":");
|
|
if (!pstr) {
|
|
goto exit;
|
|
}
|
|
|
|
#ifdef EMAIL_PORT
|
|
if (*pstr=='*') {
|
|
port=EMAIL_PORT;
|
|
} else {
|
|
port=atoi(pstr);
|
|
}
|
|
#else
|
|
port=atoi(pstr);
|
|
#endif
|
|
|
|
user=strtok(NULL,":");
|
|
if (!user) {
|
|
goto exit;
|
|
}
|
|
|
|
passwd=strtok(NULL,":");
|
|
if (!passwd) {
|
|
goto exit;
|
|
}
|
|
|
|
from=strtok(NULL,":");
|
|
if (!from) {
|
|
goto exit;
|
|
}
|
|
|
|
to=strtok(NULL,":");
|
|
if (!to) {
|
|
goto exit;
|
|
}
|
|
|
|
subject=strtok(NULL,"]");
|
|
if (!subject) {
|
|
goto exit;
|
|
}
|
|
|
|
|
|
#ifdef EMAIL_USER
|
|
if (*user=='*') {
|
|
user=xPSTR(EMAIL_USER);
|
|
}
|
|
#endif
|
|
#ifdef EMAIL_PASSWORD
|
|
if (*passwd=='*') {
|
|
passwd=xPSTR(EMAIL_PASSWORD);
|
|
}
|
|
#endif
|
|
#ifdef EMAIL_SERVER
|
|
if (*mserv=='*') {
|
|
mserv=xPSTR(EMAIL_SERVER);
|
|
}
|
|
#endif
|
|
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s - %d - %s - %s"),mserv,port,user,passwd);
|
|
#endif
|
|
|
|
#ifdef EMAIL_FROM
|
|
if (*from=='*') {
|
|
from=xPSTR(EMAIL_FROM);
|
|
}
|
|
#endif
|
|
|
|
#ifdef DEBUG_EMAIL_PORT
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s - %s - %s - %s"),from,to,subject,cmd);
|
|
#endif
|
|
|
|
smtpData.setDebug(true);
|
|
|
|
//Set the Email host, port, account and password
|
|
smtpData.setLogin(mserv, port, user, passwd);
|
|
|
|
//For library version 1.2.0 and later which STARTTLS protocol was supported,the STARTTLS will be
|
|
//enabled automatically when port 587 was used, or enable it manually using setSTARTTLS function.
|
|
//smtpData.setSTARTTLS(true);
|
|
|
|
//Set the sender name and Email
|
|
smtpData.setSender("ESP32",from);
|
|
|
|
//Set Email priority or importance High, Normal, Low or 1 to 5 (1 is highest)
|
|
smtpData.setPriority("High");
|
|
|
|
//Set the subject
|
|
smtpData.setSubject(subject);
|
|
|
|
#ifdef USE_SCRIPT
|
|
if (*cmd=='*' && *(cmd+1)==0) {
|
|
smtpData.clrMessage(true);
|
|
script_send_email_body(send_message_txt);
|
|
} else {
|
|
smtpData.setMessage(cmd, true);
|
|
}
|
|
#else
|
|
//Set the message - normal text or html format
|
|
smtpData.setMessage(cmd, true);
|
|
#endif
|
|
|
|
|
|
//Add recipients, can add more than one recipient
|
|
smtpData.addRecipient(to);
|
|
|
|
//Add attachments, can add the file or binary data from flash memory, file in SD card
|
|
//Data from internal memory
|
|
//smtpData.addAttachData("firebase_logo.png", "image/png", (uint8_t *)dummyImageData, sizeof dummyImageData);
|
|
|
|
//Add attach files from SD card
|
|
//Comment these two lines, if no SD card connected
|
|
//Two files that previousely created.
|
|
//smtpData.addAttachFile("/binary_file.dat");
|
|
//smtpData.addAttachFile("/text_file.txt");
|
|
|
|
|
|
//Add some custom header to message
|
|
//See https://tools.ietf.org/html/rfc822
|
|
//These header fields can be read from raw or source of message when it received)
|
|
//smtpData.addCustomMessageHeader("Date: Sat, 10 Aug 2019 21:39:56 -0700 (PDT)");
|
|
//Be careful when set Message-ID, it should be unique, otherwise message will not store
|
|
//smtpData.addCustomMessageHeader("Message-ID: <abcde.fghij@gmail.com>");
|
|
|
|
//Set the storage types to read the attach files (SD is default)
|
|
//smtpData.setFileStorageType(MailClientStorageType::SPIFFS);
|
|
#if defined (USE_SCRIPT) && defined(USE_SCRIPT_FATFS)
|
|
smtpData.setFileStorageType(MailClientStorageType::SD);
|
|
#endif
|
|
//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());
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("Error sending Email, %s"), MailClient.smtpErrorReason());
|
|
|
|
} else {
|
|
status=0;
|
|
}
|
|
//Clear all data from Email object to free memory
|
|
smtpData.empty();
|
|
|
|
exit:
|
|
if (oparams) free(oparams);
|
|
return status;
|
|
}
|
|
|
|
|
|
void send_message_txt(char *txt) {
|
|
if (*txt=='&') {
|
|
txt++;
|
|
smtpData.addAttachFile(txt);
|
|
} else if (*txt=='$') {
|
|
txt++;
|
|
#if defined(ESP32) && defined(USE_WEBCAM)
|
|
uint32_t cnt;
|
|
uint8_t *buff;
|
|
uint32_t len,picmax;
|
|
picmax=WcGetPicstore(-1,0);
|
|
cnt=*txt&7;
|
|
if (cnt<1 || cnt>picmax) cnt=1;
|
|
len=WcGetPicstore(cnt-1,&buff);
|
|
if (len) {
|
|
char str[12];
|
|
sprintf(str,"img_%1d.jpg",cnt+1);
|
|
smtpData.addAttachData(str, "image/jpg",buff,len);
|
|
}
|
|
#endif
|
|
} else {
|
|
smtpData.addMessage(txt);
|
|
}
|
|
}
|
|
|
|
/*
|
|
//Callback function to get the Email sending status
|
|
void sendCallback(SendStatus msg)
|
|
{
|
|
//Print the current status
|
|
Serial.println(msg.info());
|
|
|
|
//Do something when complete
|
|
if (msg.success())
|
|
{
|
|
Serial.println("----------------");
|
|
}
|
|
}
|
|
*/
|
|
#endif
|
|
|
|
|
|
#endif // USE_SENDMAIL
|