Em um post anterior eu mostrei como se enviava e-mail e adverti para o fato de que a conexão não era segura e as credenciais podiam ser interceptadas (além do fato óbvio do e-mail poder ser lido). Eu achei que enviar por uma conexão segura fosse muito complicado, mas descobri que não é. O problema é que usa muita RAM. O email sem criptografia te deixa com 46KB livres para o resto do seu programa enquanto este aqui te deixa com “apenas” 18KB. Lembre-se de que isso ainda é 9x a RAM total de um Arduino UNO.
Sobre fingerprints e validação de certificado
Se você usa um servidor de e-mail numa conta compartilhada, como é o caso da hostgator, o certificado não vai validar se você colocar o nome do seu domínio como servidor. Você tem que obter o nome correto do servidor de e-mail que atende a sua conta. Na hostgator isso pode ser visto no cPanel.
Por exemplo, meu servidor de e-mail normal seria: meudominio.com.br ou mail.meudominio.com.br mas para validar o certificado eu preciso colocar gator1234.hostgator.com.
O exemplo abaixo é uma adaptação simples do exemplo que não usa criptografia.
/* * Envio de e-mail por SMTP usando conexão criptografada * Jefferson Ryan - automalabs.com.br - Julho de 2017 * Testado em um ESP8266 - ESP-01 - IDE Arduino 1.8.1 e ESP8266 Core v2.3.0 * Mais informações em http://www.automalabs.com.br/?p=1595 * */ #include <ESP8266WiFi.h> #include <WiFiClientSecure.h> //======== Você precisa preencher estes dados =========================================== const char* SSID = ""; const char* PASS = ""; char smtp_server[] = ""; const int smtp_port = 465; //465 é a porta segura no meu servidor. A sua pode ser outra. const String mail_username="nome_do_usuario"; const String mail_password="senha"; const String mail_from="ESP8266 <usuario@servidor_remetente>"; const String mail_to="Jefferson <usuario@servidor_destino>"; const String mail_subject="Enviado pelo ESP8266"; const String mail_line1="Esta é a linha 1\n"; const String mail_line2="Esta é a linha 2"; const String mail_line3="Esta é a linha 3"; //Obtenha com a ajuda de https://www.grc.com/fingerprints.htm //Precisará ser atualizado manualmente quando o certificado expirar const char* fingerprint = ""; //========================================================================================= bool construindoLinha=false; const char* _b64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; // Cria uma conexao SSL/TLS WiFiClientSecure client; void printFreeRAM(){ Serial.print("RAM livre: "); Serial.print(ESP.getFreeHeap()); Serial.println(" bytes."); } void 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 base64_encode(char *output, const char *input, int inputLen) { 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; } void setup() { Serial.begin(115200); // Serial.setDebugOutput(true); delay(10); Serial.println(""); Serial.println(""); Serial.print("Conectando a: "); Serial.println(SSID); Serial.print("Com a senha: "); Serial.println(PASS); WiFi.begin(SSID, PASS); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi Conectado."); Serial.print("Endereco IP local: "); Serial.println(WiFi.localIP()); printFreeRAM(); byte ret = sendEmail(); printFreeRAM(); } void loop() { } void SEND(String message) { if (!construindoLinha){Serial.print("EU: ");}; //Imprimo apenas no início de cada linha Serial.print (message); client.print (message); construindoLinha=true; } void SENDln(String message) { if (!construindoLinha){Serial.print("EU: ");}; //Imprimo apenas no início de cada linha Serial.println (message); client.println (message); construindoLinha=false; } byte sendEmail() { byte thisByte = 0; byte respCode; Serial.print("Conectando a: "); Serial.println(smtp_server); if (!client.connect(smtp_server, smtp_port)) { Serial.println("Falha na conexao."); return 0; }else { Serial.println("Conectado."); } if (client.verify(fingerprint,smtp_server)) { Serial.println("O certificado confere."); } else { Serial.println("O certificado nao confere."); //return 0; //Descomente esta linha para impedir o envio se o certificado estiver errado } if (!eRcv()) return 0; char* buf = (char*)malloc(100); SEND("EHLO "); SENDln(smtp_server); if (!eRcv()) return 0; SENDln("auth login"); if (!eRcv()) return 0; base64_encode(buf, mail_username.c_str(), mail_username.length()); client.println(buf); Serial.println(buf); if (!eRcv()) return 0; base64_encode(buf, mail_password.c_str(), mail_password.length()); client.println(buf); Serial.println(buf); if (!eRcv()) return 0; SEND("MAIL From: "); SENDln(mail_from); if (!eRcv()) return 0; SEND("RCPT To: "); SENDln(mail_to); if (!eRcv()) return 0; SENDln("DATA"); if (!eRcv()) return 0; SEND("To: "); SENDln(mail_to); SEND("From: "); SENDln(mail_from); //Este é o "nome para exibição" SEND("Subject: "); SENDln(mail_subject); SENDln(mail_line1); SENDln(mail_line2); SENDln(mail_line3); SENDln("."); //O email tem que terminar assim if (!eRcv()) return 0; SENDln("QUIT"); if (!eRcv()) return 0; client.stop(); Serial.println("Desconectado."); return 1; } byte eRcv() { byte respCode; byte thisByte; int loopCount = 0; while (!client.available()) { delay(1); loopCount++; // Se nada for recebido em 10s, desiste. if (loopCount > 10000) { client.stop(); Serial.println("\r\nTimeout"); return 0; } } respCode = client.peek(); while (client.available()) { thisByte = client.read(); Serial.write(thisByte); } if (respCode >= '4') { // efail(); return 0; } return 1; }
Por alto, as diferenças são 4:
1)Acrescente: #include <WiFiClientSecure.h>
2)Acrescente: const char* fingerprint = “fingerprint_aqui”;
3)Mude: WiFiClient client; para WiFiClientSecure client;
4)Acrescente a validação de certificado logo após a conexão:
if (client.verify(fingerprint,smtp_server)) { Serial.println("O certificado confere."); } else { Serial.println("O certificado nao confere."); //return 0; //Descomente esta linha para impedir o envio se o certificado estiver errado }