Tasmota/tasmota/sendemail.ino

375 lines
8.1 KiB
Arduino
Raw Normal View History

2019-10-14 09:14:17 +01:00
#ifdef USE_SENDMAIL
2019-09-04 19:58:17 +01:00
#include "sendemail.h"
// enable serial debugging
2019-10-20 10:21:25 +01:00
//#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
2019-10-18 10:33:52 +01:00
//HW Watchdog 8.44 sec.
//SW Watchdog 3.2 sec.
2019-10-20 10:21:25 +01:00
#ifndef SEND_MAIL_MINRAM
2019-10-18 10:33:52 +01:00
#define SEND_MAIL_MINRAM 12*1024
2019-10-20 10:21:25 +01:00
#endif
#define xPSTR(a) a
2019-10-18 10:33:52 +01:00
uint16_t SendMail(char *buffer) {
char *params,*oparams;
2019-10-20 10:21:25 +01:00
const char *mserv;
2019-10-18 10:33:52 +01:00
uint16_t port;
2019-10-20 10:21:25 +01:00
const char *user;
const char *pstr;
const char *passwd;
const char *from;
const char *to;
const char *subject;
const char *cmd;
char auth=0;
2019-10-18 10:33:52 +01:00
uint16_t status=1;
SendEmail *mail=0;
uint16_t blen;
char *endcmd;
// return if not enough memory
2020-04-22 15:07:52 +01:00
uint16_t mem=ESP_getFreeHeap();
2019-10-18 10:33:52 +01:00
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
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("mailsize: %d"),blen);
2019-10-18 10:33:52 +01:00
#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=='*') {
2019-10-20 10:21:25 +01:00
user=xPSTR(EMAIL_USER);
2019-10-18 10:33:52 +01:00
}
#endif
#ifdef EMAIL_PASSWORD
if (*passwd=='*') {
2019-10-20 10:21:25 +01:00
passwd=xPSTR(EMAIL_PASSWORD);
2019-10-18 10:33:52 +01:00
}
#endif
#ifdef EMAIL_SERVER
if (*mserv=='*') {
2019-10-20 10:21:25 +01:00
mserv=xPSTR(EMAIL_SERVER);
2019-10-18 10:33:52 +01:00
}
#endif //USE_SENDMAIL
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s - %d - %s - %s"),mserv,port,user,passwd);
2019-10-18 10:33:52 +01:00
#endif
// 2 seconds timeout
2019-10-20 10:21:25 +01:00
#ifndef MAIL_TIMEOUT
2019-10-20 10:34:29 +01:00
#define MAIL_TIMEOUT 2000
2019-10-20 10:21:25 +01:00
#endif
2019-10-18 10:33:52 +01:00
mail = new SendEmail(mserv,port,user,passwd, MAIL_TIMEOUT, auth);
#ifdef EMAIL_FROM
if (*from=='*') {
2019-10-20 10:21:25 +01:00
from=xPSTR(EMAIL_FROM);
2019-10-18 10:33:52 +01:00
}
#endif
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s - %s - %s - %s"),from,to,subject,cmd);
2019-10-18 10:33:52 +01:00
#endif
if (mail) {
bool result=mail->send(from,to,subject,cmd);
delete mail;
if (result==true) status=0;
}
2019-09-04 19:58:17 +01:00
2019-10-18 10:33:52 +01:00
exit:
if (oparams) free(oparams);
return status;
2019-09-04 19:58:17 +01:00
}
2020-04-12 18:28:19 +01:00
#ifdef ESP8266
2019-10-20 10:21:25 +01:00
void script_send_email_body(BearSSL::WiFiClientSecure_light *client);
2019-10-18 10:33:52 +01:00
SendEmail::SendEmail(const String& host, const int port, const String& user, const String& passwd, const int timeout, const int auth_used) :
2019-10-20 10:21:25 +01:00
host(host), port(port), user(user), passwd(passwd), timeout(timeout), ssl(ssl), auth_used(auth_used), client(new BearSSL::WiFiClientSecure_light(1024,1024)) {
2019-10-18 10:33:52 +01:00
}
2020-04-12 18:28:19 +01:00
#else
void script_send_email_body(WiFiClient *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
2019-10-18 10:33:52 +01:00
String SendEmail::readClient() {
delay(0);
2019-09-04 19:58:17 +01:00
String r = client->readStringUntil('\n');
2019-10-18 10:33:52 +01:00
2019-09-04 19:58:17 +01:00
r.trim();
while (client->available()) {
delay(0);
r += client->readString();
}
return r;
}
2019-10-20 10:21:25 +01:00
bool SendEmail::send(const String& from, const String& to, const String& subject, const char *msg) {
2019-10-18 10:33:52 +01:00
bool status=false;
String buffer;
if (!host.length()) {
return status;
2019-09-04 19:58:17 +01:00
}
2019-10-18 10:33:52 +01:00
2019-09-04 19:58:17 +01:00
client->setTimeout(timeout);
// smtp connect
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("Connecting: %s on port %d"),host.c_str(),port);
2019-09-04 19:58:17 +01:00
#endif
2019-10-18 10:33:52 +01:00
if (!client->connect(host.c_str(), port)) {
2019-09-04 19:58:17 +01:00
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P(LOG_LEVEL_INFO, PSTR("Connection failed"));
2019-09-04 19:58:17 +01:00
#endif
2019-10-18 10:33:52 +01:00
goto exit;
2019-09-04 19:58:17 +01:00
}
2019-10-18 10:33:52 +01:00
buffer = readClient();
2019-09-04 19:58:17 +01:00
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
2019-10-18 10:33:52 +01:00
if (!buffer.startsWith(F("220"))) {
goto exit;
2019-09-04 19:58:17 +01:00
}
buffer = F("EHLO ");
buffer += client->localIP().toString();
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
2019-10-18 10:33:52 +01:00
if (!buffer.startsWith(F("250"))) {
goto exit;
2019-09-04 19:58:17 +01:00
}
2019-10-18 10:33:52 +01:00
if (user.length()>0 && passwd.length()>0 ) {
2019-09-04 19:58:17 +01:00
buffer = F("AUTH LOGIN");
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
if (!buffer.startsWith(F("334")))
{
2019-10-18 10:33:52 +01:00
goto exit;
2019-09-04 19:58:17 +01:00
}
base64 b;
buffer = b.encode(user);
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
2019-10-18 10:33:52 +01:00
if (!buffer.startsWith(F("334"))) {
goto exit;
2019-09-04 19:58:17 +01:00
}
buffer = b.encode(passwd);
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
2019-10-18 10:33:52 +01:00
if (!buffer.startsWith(F("235"))) {
goto exit;
2019-09-04 19:58:17 +01:00
}
}
// smtp send mail
buffer = F("MAIL FROM:");
buffer += from;
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
2019-10-18 10:33:52 +01:00
if (!buffer.startsWith(F("250"))) {
goto exit;
2019-09-04 19:58:17 +01:00
}
buffer = F("RCPT TO:");
buffer += to;
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
2019-10-18 10:33:52 +01:00
if (!buffer.startsWith(F("250"))) {
goto exit;
2019-09-04 19:58:17 +01:00
}
buffer = F("DATA");
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
2019-10-18 10:33:52 +01:00
if (!buffer.startsWith(F("354"))) {
goto exit;
2019-09-04 19:58:17 +01:00
}
buffer = F("From: ");
buffer += from;
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
buffer = F("To: ");
buffer += to;
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
buffer = F("Subject: ");
buffer += subject;
buffer += F("\r\n");
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
2019-10-18 10:33:52 +01:00
2019-10-20 10:21:25 +01:00
#ifdef USE_SCRIPT
if (*msg=='*' && *(msg+1)==0) {
script_send_email_body(client);
} else {
client->println(msg);
}
#else
2019-10-18 10:33:52 +01:00
client->println(msg);
2019-10-20 10:21:25 +01:00
#endif
2019-09-04 19:58:17 +01:00
client->println('.');
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
2019-10-18 10:33:52 +01:00
2019-09-04 19:58:17 +01:00
buffer = F("QUIT");
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
2019-10-20 10:21:25 +01:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("%s"),buffer.c_str());
2019-09-04 19:58:17 +01:00
#endif
2019-10-18 10:33:52 +01:00
status=true;
exit:
2019-09-04 19:58:17 +01:00
2019-10-18 10:33:52 +01:00
return status;
2019-09-04 19:58:17 +01:00
}
2019-10-18 10:33:52 +01:00
2019-10-14 09:14:17 +01:00
#endif // USE_SENDMAIL