mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-24 11:16:34 +00:00
sendmail
This commit is contained in:
parent
af1edb0cdb
commit
ca52a38bc1
302
lib/SENDMAIL/sendemail.cpp
Executable file
302
lib/SENDMAIL/sendemail.cpp
Executable file
@ -0,0 +1,302 @@
|
||||
#include "sendemail.h"
|
||||
|
||||
// enable serial debugging
|
||||
//#define DEBUG_EMAIL_PORT Serial
|
||||
|
||||
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())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
String SendEmail::readClient()
|
||||
{
|
||||
String r = client->readStringUntil('\n');
|
||||
r.trim();
|
||||
while (client->available()) {
|
||||
delay(0);
|
||||
r += client->readString();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void SetSerialBaudrate(int baudrate);
|
||||
|
||||
bool SendEmail::send(const String& from, const String& to, const String& subject, const String& msg)
|
||||
{
|
||||
if (!host.length())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
client->setTimeout(timeout);
|
||||
// smtp connect
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
SetSerialBaudrate(115200);
|
||||
DEBUG_EMAIL_PORT.print("Connecting: ");
|
||||
DEBUG_EMAIL_PORT.print(host);
|
||||
DEBUG_EMAIL_PORT.print(":");
|
||||
DEBUG_EMAIL_PORT.println(port);
|
||||
#endif
|
||||
|
||||
#ifndef ARDUINO_ESP8266_RELEASE_2_4_2
|
||||
client->setInsecure();
|
||||
bool mfln = client->probeMaxFragmentLength(host.c_str(), port, 512);
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.printf("MFLN supported: %s\n", mfln ? "yes" : "no");
|
||||
#endif
|
||||
if (mfln) {
|
||||
client->setBufferSizes(512, 512);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!client->connect(host.c_str(), port))
|
||||
{
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println("Connection failed");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
String buffer = readClient();
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
if (!buffer.startsWith(F("220")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
buffer = F("EHLO ");
|
||||
buffer += client->localIP().toString();
|
||||
|
||||
client->println(buffer);
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
buffer = readClient();
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
if (!buffer.startsWith(F("250")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (user.length()>0 && passwd.length()>0 )
|
||||
{
|
||||
|
||||
//buffer = F("STARTTLS");
|
||||
//client->println(buffer);
|
||||
|
||||
if (auth_used==1) {
|
||||
// plain
|
||||
#ifdef USE_PLAIN
|
||||
buffer = F("AUTH PLAIN");
|
||||
client->println(buffer);
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
buffer = readClient();
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
if (!buffer.startsWith(F("334")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char plainAuth[100];
|
||||
memset(plainAuth,sizeof(plainAuth),0);
|
||||
plainAuth[0] = '\0';
|
||||
strcpy(&plainAuth[1], user.c_str());
|
||||
strcpy(&plainAuth[2+user.length()],passwd.c_str());
|
||||
const char* pA = (const char*)&plainAuth;
|
||||
char buf[100];
|
||||
base64_encode(buf, pA, user.length()+passwd.length()+2);
|
||||
client->println(buf);
|
||||
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buf);
|
||||
#endif
|
||||
buffer = readClient();
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
if (!buffer.startsWith(F("235")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
buffer = F("AUTH LOGIN");
|
||||
client->println(buffer);
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
buffer = readClient();
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
if (!buffer.startsWith(F("334")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
base64 b;
|
||||
//buffer = user;
|
||||
//buffer = b.encode(buffer);
|
||||
buffer = b.encode(user);
|
||||
|
||||
client->println(buffer);
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
//DEBUG_EMAIL_PORT.println(user);
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
buffer = readClient();
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
if (!buffer.startsWith(F("334")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//buffer = this->passwd;
|
||||
//buffer = b.encode(buffer);
|
||||
buffer = b.encode(passwd);
|
||||
client->println(buffer);
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
//DEBUG_EMAIL_PORT.println(passwd);
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
buffer = readClient();
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
if (!buffer.startsWith(F("235")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// smtp send mail
|
||||
buffer = F("MAIL FROM:");
|
||||
buffer += from;
|
||||
client->println(buffer);
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
buffer = readClient();
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
if (!buffer.startsWith(F("250")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
buffer = F("RCPT TO:");
|
||||
buffer += to;
|
||||
client->println(buffer);
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
buffer = readClient();
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
if (!buffer.startsWith(F("250")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
buffer = F("DATA");
|
||||
client->println(buffer);
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
buffer = readClient();
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
if (!buffer.startsWith(F("354")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
buffer = F("From: ");
|
||||
buffer += from;
|
||||
client->println(buffer);
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
buffer = F("To: ");
|
||||
buffer += to;
|
||||
client->println(buffer);
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
buffer = F("Subject: ");
|
||||
buffer += subject;
|
||||
buffer += F("\r\n");
|
||||
client->println(buffer);
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
buffer = msg;
|
||||
client->println(buffer);
|
||||
client->println('.');
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
buffer = F("QUIT");
|
||||
client->println(buffer);
|
||||
#ifdef DEBUG_EMAIL_PORT
|
||||
DEBUG_EMAIL_PORT.println(buffer);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef USE_PLAIN
|
||||
void SendEmail::a3_to_a4(unsigned char * a4, unsigned char * a3) {
|
||||
a4[0] = (a3[0] & 0xfc) >> 2;
|
||||
a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
|
||||
a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
|
||||
a4[3] = (a3[2] & 0x3f);
|
||||
}
|
||||
|
||||
int SendEmail::base64_encode(char *output, const char *input, int inputLen) {
|
||||
const char* _b64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
int i = 0, j = 0;
|
||||
int encLen = 0;
|
||||
unsigned char a3[3];
|
||||
unsigned char a4[4];
|
||||
while(inputLen--) {
|
||||
a3[i++] = *(input++);
|
||||
if(i == 3) {
|
||||
a3_to_a4(a4, a3);
|
||||
for(i = 0; i < 4; i++) {
|
||||
output[encLen++] = _b64_alphabet[a4[i]];
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
if(i) {
|
||||
for(j = i; j < 3; j++) {
|
||||
a3[j] = '\0';
|
||||
}
|
||||
a3_to_a4(a4, a3);
|
||||
for(j = 0; j < i + 1; j++) {
|
||||
output[encLen++] = _b64_alphabet[a4[j]];
|
||||
}
|
||||
while((i++ < 3)) {
|
||||
output[encLen++] = '=';
|
||||
}
|
||||
}
|
||||
output[encLen] = '\0';
|
||||
return encLen;
|
||||
}
|
||||
#endif
|
39
lib/SENDMAIL/sendemail.h
Executable file
39
lib/SENDMAIL/sendemail.h
Executable file
@ -0,0 +1,39 @@
|
||||
#ifndef __SENDEMAIL_H
|
||||
#define __SENDEMAIL_H
|
||||
|
||||
//#define DEBUG_EMAIL_PORT
|
||||
|
||||
#include <WiFiClient.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <base64.h>
|
||||
#include <core_version.h>
|
||||
|
||||
class SendEmail
|
||||
{
|
||||
private:
|
||||
const String host;
|
||||
const int port;
|
||||
const String user;
|
||||
const String passwd;
|
||||
const int timeout;
|
||||
const bool ssl;
|
||||
const int auth_used;
|
||||
#ifndef ARDUINO_ESP8266_RELEASE_2_4_2
|
||||
// use bear ssl
|
||||
// #include "WiFiClientSecureLightBearSSL.h"
|
||||
// BearSSL::WiFiClientSecure_light *client;
|
||||
//BearSSL::WiFiClientSecure* client;
|
||||
WiFiClientSecure* client;
|
||||
#else
|
||||
WiFiClient* client;
|
||||
#endif
|
||||
String readClient();
|
||||
void a3_to_a4(unsigned char * a4, unsigned char * a3);
|
||||
int base64_encode(char *output, const char *input, int inputLen);
|
||||
public:
|
||||
SendEmail(const String& host, const int port, const String& user, const String& passwd, const int timeout, const int auth_used);
|
||||
bool send(const String& from, const String& to, const String& subject, const String& msg);
|
||||
~SendEmail() {client->stop(); delete client;}
|
||||
};
|
||||
|
||||
#endif
|
@ -1053,6 +1053,7 @@ bool HandleRootStatusRefresh(void)
|
||||
#ifdef USE_SCRIPT_WEB_DISPLAY
|
||||
XdrvCall(FUNC_WEB_SENSOR);
|
||||
#endif
|
||||
|
||||
WSContentSend_P(PSTR("</table>"));
|
||||
|
||||
if (devices_present) {
|
||||
@ -2350,6 +2351,151 @@ String UrlEncode(const String& text)
|
||||
return encoded;
|
||||
}
|
||||
|
||||
#ifdef USE_SENDMAIL
|
||||
|
||||
#include "sendemail.h"
|
||||
|
||||
//SendEmail(const String& host, const int port, const String& user, const String& passwd, const int timeout, const bool ssl);
|
||||
//SendEmail::send(const String& from, const String& to, const String& subject, const String& msg)
|
||||
// sendmail [server:port:user:passwd:from:to:subject] data
|
||||
// sendmail [*:*:*:*:*:to:subject] data uses defines from user_config
|
||||
// sendmail currently only works with core 2.4.2
|
||||
|
||||
#define SEND_MAIL_MINRAM 19*1024
|
||||
|
||||
uint16_t SendMail(char *buffer) {
|
||||
uint16_t count;
|
||||
char *params,*oparams;
|
||||
char *mserv;
|
||||
uint16_t port;
|
||||
char *user;
|
||||
char *pstr;
|
||||
char *passwd;
|
||||
char *from;
|
||||
char *to;
|
||||
char *subject;
|
||||
char *cmd;
|
||||
char secure=0,auth=0;
|
||||
uint16_t status=1;
|
||||
SendEmail *mail=0;
|
||||
|
||||
//DebugFreeMem();
|
||||
|
||||
// return if not enough memory
|
||||
uint16_t mem=ESP.getFreeHeap();
|
||||
if (mem<SEND_MAIL_MINRAM) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
while (*buffer==' ') buffer++;
|
||||
|
||||
// copy params
|
||||
oparams=(char*)calloc(strlen(buffer)+2,1);
|
||||
if (!oparams) return 4;
|
||||
|
||||
params=oparams;
|
||||
|
||||
strcpy(params,buffer);
|
||||
|
||||
if (*params=='p') {
|
||||
auth=1;
|
||||
params++;
|
||||
}
|
||||
|
||||
if (*params!='[') {
|
||||
goto exit;
|
||||
}
|
||||
params++;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
cmd=subject+strlen(subject)+1;
|
||||
|
||||
#ifdef EMAIL_USER
|
||||
if (*user=='*') {
|
||||
user=(char*)EMAIL_USER;
|
||||
}
|
||||
#endif
|
||||
#ifdef EMAIL_PASSWORD
|
||||
if (*passwd=='*') {
|
||||
passwd=(char*)EMAIL_PASSWORD;
|
||||
}
|
||||
#endif
|
||||
#ifdef EMAIL_SERVER
|
||||
if (*mserv=='*') {
|
||||
mserv=(char*)EMAIL_SERVER;
|
||||
}
|
||||
#endif //USE_SENDMAIL
|
||||
|
||||
// auth = 0 => AUTH LOGIN 1 => PLAIN LOGIN
|
||||
// 2 seconds timeout
|
||||
#define MAIL_TIMEOUT 2000
|
||||
mail = new SendEmail(mserv, port,user,passwd, MAIL_TIMEOUT, auth);
|
||||
|
||||
#ifdef EMAIL_FROM
|
||||
if (*from=='*') {
|
||||
from=(char*)EMAIL_FROM;
|
||||
}
|
||||
#endif
|
||||
|
||||
exit:
|
||||
if (mail) {
|
||||
bool result=mail->send(from,to,subject,cmd);
|
||||
delete mail;
|
||||
if (result==true) status=0;
|
||||
}
|
||||
|
||||
|
||||
if (oparams) free(oparams);
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int WebSend(char *buffer)
|
||||
{
|
||||
// [sonoff] POWER1 ON --> Sends http://sonoff/cm?cmnd=POWER1 ON
|
||||
@ -2462,17 +2608,27 @@ bool JsonWebColor(const char* dataBuf)
|
||||
return true;
|
||||
}
|
||||
|
||||
const char kWebSendStatus[] PROGMEM = D_JSON_DONE "|" D_JSON_WRONG_PARAMETERS "|" D_JSON_CONNECT_FAILED "|" D_JSON_HOST_NOT_FOUND ;
|
||||
#define D_CMND_SENDMAIL "sendmail"
|
||||
#define D_JSON_MEMORY_ERROR "memory error"
|
||||
|
||||
|
||||
const char kWebSendStatus[] PROGMEM = D_JSON_DONE "|" D_JSON_WRONG_PARAMETERS "|" D_JSON_CONNECT_FAILED "|" D_JSON_HOST_NOT_FOUND "|" D_JSON_MEMORY_ERROR;
|
||||
|
||||
const char kWebCommands[] PROGMEM = "|" // No prefix
|
||||
#ifdef USE_EMULATION
|
||||
D_CMND_EMULATION "|"
|
||||
#endif
|
||||
#ifdef USE_SENDMAIL
|
||||
D_CMND_SENDMAIL "|"
|
||||
#endif
|
||||
D_CMND_WEBSERVER "|" D_CMND_WEBPASSWORD "|" D_CMND_WEBLOG "|" D_CMND_WEBREFRESH "|" D_CMND_WEBSEND "|" D_CMND_WEBCOLOR "|" D_CMND_WEBSENSOR;
|
||||
|
||||
void (* const WebCommand[])(void) PROGMEM = {
|
||||
#ifdef USE_EMULATION
|
||||
&CmndEmulation,
|
||||
#endif
|
||||
#ifdef USE_SENDMAIL
|
||||
&CmndSendmail,
|
||||
#endif
|
||||
&CmndWebServer, &CmndWebPassword, &CmndWeblog, &CmndWebRefresh, &CmndWebSend, &CmndWebColor, &CmndWebSensor };
|
||||
|
||||
@ -2500,6 +2656,18 @@ void CmndEmulation(void)
|
||||
}
|
||||
#endif // USE_EMULATION
|
||||
|
||||
#ifdef USE_SENDMAIL
|
||||
void CmndSendmail(void)
|
||||
{
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
uint8_t result = SendMail(XdrvMailbox.data);
|
||||
char stemp1[20];
|
||||
ResponseCmndChar(GetTextIndexed(stemp1, sizeof(stemp1), result, kWebSendStatus));
|
||||
}
|
||||
}
|
||||
#endif // USE_SENDMAIL
|
||||
|
||||
|
||||
void CmndWebServer(void)
|
||||
{
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user