"SOLUCIONADO" EMAIL USANDO SHIELD ETHERNET

Buenas a todos se que me dirán que buscando en google lo habría encontrado pero os garantizo que he buscado y mucho y mas cosas que he intentado ya no se que hacer para conseguir mandar un email desde arduino con una alarma a mi correo si alguien del foro me pudiese hechar una mano le estaría muy agradecido.

Buenas, enviar mail con arduino, no es dificil pero tampoco es escribir el texto y darle a "enviar". Yo en su día, lo solucioné con la funcionalidad de telnet del servidor de mail del proveedor de mi dominio. Supongo que tienes claro como configurar la parte del ethernet, de forma que voy a ir directo al tema del envío del mail.

Lo primero que tienes que hacer, es definir el servidor de mail, en la zona de declaración de variables locales (al principio del sketch) y declarar el cliente.

char mailserver[] = "smtp.tudominio.com"; //Mailserver
EthernetClient client;

Lo siguiente, es añadir este código, FUERA del loop

byte sendEmail()
{
  byte thisByte = 0;
  byte respCode;

  if (client.connect(mailserver, 25) == 1) {
  } else {
    return 0;
  }

  if (!eRcv()) return 0;

  // Autenticacion mailserver
  client.println(F("AUTH LOGIN"));
  client.println(F("dXN1YXJpbw==")); //usuario encriptado en base 64
  client.println(F("cGFzc3dvcmQ=")); //password encriptado en base 64

  if (!eRcv()) return 0;

  // Direccion de mail "desde"
  client.println(F("MAIL From: <tuemail@tudominio.com>")); //Direccion de mail desde la que envias

  if (!eRcv()) return 0;

  // Envia a...
  client.println(F("RCPT To: <destinatario@sudominio.com>")); //Direccion de mail hacia la que envias

  if (!eRcv()) return 0;

  client.println(F("DATA"));

  if (!eRcv()) return 0;


  // De nuevo, la direccion de mail del destinatario, que ademas, se le puede añadir el nombre
  client.println(F("To: NombreDestinatario <destinatario@sudominio.com>"));

  // Lo mismo, pero con el que envia
  client.println(F("From: MiNombre <tuemail@tudominio.com>"));

  client.println(F("Subject: Aqui ponemos el texto del asunto del mail\r\n"));

  client.println(F("Aqui ponemos el texto del cuerpo del mail"));

  client.println(F("."));

  if (!eRcv()) return 0;

  client.println(F("QUIT"));

  if (!eRcv()) return 0;

  client.stop();


  return 1;
}

byte eRcv()
{
  byte respCode;
  byte thisByte;
  int loopCount = 0;

  while (!client.available()) {
    delay(1);
    loopCount++;

    // if nothing received for 10 seconds, timeout
    if (loopCount > 10000) {
      client.stop();
      return 0;
    }
  }

  respCode = client.peek();

  while (client.available())
  {
    thisByte = client.read();
  }

  if (respCode >= '4')
  {
    efail();
    return 0;
  }

  return 1;
}


void efail()
{
  byte thisByte = 0;
  int loopCount = 0;

  client.println(F("QUIT"));

  while (!client.available()) {
    delay(1);
    loopCount++;

    // if nothing received for 10 seconds, timeout
    if (loopCount > 10000) {
      client.stop();
      return;
    }
  }

  while (client.available())
  {
    thisByte = client.read();
  }

  client.stop();

}

Mira los comentarios, ya que indican donde tienes que poner las direcciones de mail de origen y de destino.

Por último, cada vez que llames la función

sendEmail()

dentro del loop, se enviará el mail. Mucho cuidado con esto, ya que si lo pones en el loop sin más, se enviarán un montón de mails, y podrías saturar el servidor, e incluso te podrían meter tu dirección de mail en una lista de spam.

Casi se me olvida, para poder encriptar el usuario y el password de tu servidor SMTP, puedes usar el siguiente link:

Normalmente, es obligatorio poner esas dos cosas encriptadas, ya que si no, no funciona.

me podrías explicar también como se establece la conexión de internet.
gracias

Dependerá de qué uses para conectar el arduino a la red. No sé si usas ethernet shield, wifi shield, esp8266, sim900, gsm shield...

Básicamente, tienes que configurar una ip, máscara de red, puerta de enlace y dns, pero esa configuración, variará según el hardware que uses. Mis favoritos son los ethernet y wifi shields. Son más caros (el ethernet se puede encontrar bien de precio) pero son muy fáciles de configurar, y usan librerias oficiales standard, que funcionan muy bien.

Uso ethernet slide

Mira la documentacion de la libreria:

Básicamente, hay que configurar lo que te dije antes. Aqui tienes la sintaxis:

#include <Dhcp.h>
#include <Dns.h>
#include <Ethernet.h>
#include <EthernetClient.h>
#include <EthernetServer.h>
#include <EthernetUdp.h>
#include <SPI.h>

char mailserver[] = "smtp.gmail.com"; //Mailserver
EthernetClient client;

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };  

// the dns server ip
IPAddress dnServer(192, 168, 1, 1);
// the router's gateway address:
IPAddress gateway(192, 168,1 , 1);
// the subnet:1
IPAddress subnet(255, 255, 255, 0);

//the IP address is dependent on your network
IPAddress ip(192, 168, 1, 1);

void setup() {
  Serial.begin(9600);

  // initialize the ethernet device
  Ethernet.begin(mac, ip, dnServer, gateway, subnet);
  //print out the IP address
  Serial.print("IP = ");
  Serial.println(Ethernet.localIP());
}

void loop() {
sendEmail();
delay(100000);

}

byte sendEmail()
{
  byte thisByte = 0;
  byte respCode;

  if (client.connect(mailserver, 465) == 1) {
    Serial.println("conectado");
  } else {
    return 0;
  }

  if (!eRcv()) return 0;

  // Autenticacion mailserver
  client.println(F("AUTH LOGIN"));
  client.println(F("usuario encriptado en base 64")); //usuario encriptado en base 64
  client.println(F("password encriptado en base 64")); //password encriptado en base 64

  if (!eRcv()) return 0;

  // Direccion de mail "desde"
  client.println(F("MAIL From: <direccion desde la que envio>")); //Direccion de mail desde la que envias

  if (!eRcv()) return 0;

  // Envia a...
  client.println(F("RCPT To: <direccion a la que envio>")); //Direccion de mail hacia la que envias

  if (!eRcv()) return 0;

  client.println(F("DATA"));

  if (!eRcv()) return 0;


  // De nuevo, la direccion de mail del destinatario, que ademas, se le puede añadir el nombre
  client.println(F("To: NombreDestinatario <direccion a la que envio>"));

  // Lo mismo, pero con el que envia
  client.println(F("From: MiNombre <direccion desde la que envio>"));

  client.println(F("Subject: Aqui ponemos el texto del asunto del mail\r\n"));

  client.println(F("Aqui ponemos el texto del cuerpo del mail"));

  client.println(F("."));

  if (!eRcv()) return 0;

  client.println(F("QUIT"));

  if (!eRcv()) return 0;

  client.stop();


  return 1;
}

byte eRcv()
{
  byte respCode;
  byte thisByte;
  int loopCount = 0;

  while (!client.available()) {
    delay(1);
    loopCount++;

    // if nothing received for 10 seconds, timeout
    if (loopCount > 10000) {
      client.stop();
      return 0;
    }
  }

  respCode = client.peek();

  while (client.available())
  {
    thisByte = client.read();
  }

  if (respCode >= '4')
  {
    efail();
    return 0;
  }

  return 1;
}


void efail()
{
  byte thisByte = 0;
  int loopCount = 0;

  client.println(F("QUIT"));

  while (!client.available()) {
    delay(1);
    loopCount++;

    // if nothing received for 10 seconds, timeout
    if (loopCount > 10000) {
      client.stop();
      return;
    }
  }

  while (client.available())
  {
    thisByte = client.read();
  }

  client.stop();

}

puedes mirar el codigo haber que hago mal asi se supone que deberia de mandar correos no??

Bueno, el primer problema que se plantea aqui, es GMAIL. ¿Por qué GMAIL? pues porque el servidor de Gmail, no acepta conexiones telnet planas, si no que necesita conexión SSL, y tengo serias dudas de que un arduino sencillo, sea capaz de manejarse con los paquetes de encriptación de SSL (además de que no se ni cómo habría que hacerlo).

Yo lo uso con el servidor SMTP del dominio que tengo contratado a Nominalia, y va a la perfección, ya que permite conexiones telnet simples.

lo he probado con otra dirección con un dominio que tengo en one.com contratado y tampoco me funciona
el servidor smtp es send.one.com y puerto 465
pero nada

Con el servidor send.one.com parece que si se se puede.

Si desde una consola de DOS haces un:

telnet send.one.com 25

Te llegas a conectar al servidor

El siguiente comando a dar, es:

EHLO send.one.com

y ahí te sale como disponible el comando AUTH LOGIN PLAIN, que es el primero que nos interesa. Si sigues estos pasos con el servidor de gmail, o sea:

telnet smtp.gmail.com 25

al hacer el

ehlo smtp.gmail.com

Verás que el AUTH LOGIN, no esta disponible, y que si das el comando en cuestion te responderá:

530 5.7.0 Must issue a STARTTLS command first. 194sm19070713wmh.19 - gsmtp

O sea, que quiere que primero inicies una conexión TLS. Creo que la solución, puede pasar por el servidor send.one.com

me sigue sin funcionar podrias mirar este codigo haber si a ti te va perdona por mi torpeza:

#include <SPI.h>
#include <Ethernet.h>
 
// this must be unique
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x59, 0x67 };  
// change network settings to yours
IPAddress ip( 192, 168, 1, 55 );    
IPAddress gateway( 192, 168, 1, 1 );
IPAddress subnet( 255, 255, 255, 0 );
 
char server[] = "send.one.com";
int port = 465 ;
 
EthernetClient client;
 
void setup()
{
  Serial.begin(9600);
  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);
  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  delay(2000);
  Serial.println(F("Ready. Press 'e' to send."));
}
 
void loop()
{
  byte inChar;
 
  inChar = Serial.read();
 
  if(inChar == 'e')
  {
      if(sendEmail()) Serial.println(F("Email sent"));
      else Serial.println(F("Email failed"));
  }
}
 
byte sendEmail()
{
  byte thisByte = 0;
  byte respCode;
 
  if(client.connect(server,port) == 1) {
    Serial.println(F("connected"));
  } else {
    Serial.println(F("connection failed"));
    return 0;
  }
 
  if(!eRcv()) return 0;
 
  Serial.println(F("Sending hello"));
  client.println("EHLO send.one.com");
  if(!eRcv()) return 0;
 
  Serial.println(F("Sending auth login"));
  client.println("auth login");
  if(!eRcv()) return 0;
 
  Serial.println(F(""));//direcion en base 64
// Change to your base64 encoded user
  client.println("xxxx");
 
  if(!eRcv()) return 0;
 
  Serial.println(F("Sending Password"));
// change to your base64 encoded password
  client.println(" ");//clave en base 64
 
  if(!eRcv()) return 0;
 
// change to your email address (sender)
  Serial.println(F("Sending From"));
  client.println("MAIL From: <          >");///////////
  if(!eRcv()) return 0;
 
// change to recipient address
  Serial.println(F("Sending To"));
  client.println("RCPT To: <manu86_moriles@hotmail.com>");
  if(!eRcv()) return 0;
 
  Serial.println(F("Sending DATA"));
  client.println("DATA");
  if(!eRcv()) return 0;
 
  Serial.println(F("Sending email"));
 
// change to recipient address
  client.println("To: You <        >");
 
// change to your address
  client.println("From: Me <                   >");
 
  client.println("Subject: Arduino email test\r\n");
 
  client.println("This is from my Arduino!");
 
  client.println(".");
 
  if(!eRcv()) return 0;
 
  Serial.println(F("Sending QUIT"));
  client.println("QUIT");
  if(!eRcv()) return 0;
 
  client.stop();
 
  Serial.println(F("disconnected"));
 
  return 1;
}
 
byte eRcv()
{
  byte respCode;
  byte thisByte;
  int loopCount = 0;
 
  while(!client.available()) {
    delay(1);
    loopCount++;
 
    // if nothing received for 10 seconds, timeout
    if(loopCount > 10000) {
      client.stop();
      Serial.println(F("\r\nTimeout"));
      return 0;
    }
  }
 
  respCode = client.peek();
 
  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  }
 
  if(respCode >= '4')
  {
    efail();
    return 0;  
  }
 
  return 1;
}
 
 
void efail()
{
  byte thisByte = 0;
  int loopCount = 0;
 
  client.println(F("QUIT"));
 
  while(!client.available()) {
    delay(1);
    loopCount++;
 
    // if nothing received for 10 seconds, timeout
    if(loopCount > 10000) {
      client.stop();
      Serial.println(F("\r\nTimeout"));
      return;
    }
  }
 
  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  }
 
  client.stop();
 
  Serial.println(F("disconnected"));
}

Bueno, el código tiene un error muy leve, y es este:

int port = 465 ;

La línea correcta es esta:

int port = 25;

¿Por qué 25? Simple. Como te dije en el post anterior, la comunicación se realiza a través de telnet, pero por el puerto 25

carmeloco:
Con el servidor send.one.com parece que si se se puede.

Si desde una consola de DOS haces un:

telnet send.one.com 25

Se usa este puerto como una especie de standard, pero no hay que confundirlo con el puerto que usamos en el gestor de email del ordenador, ya que esa transmisión es SECURE SMTP, no TELNET.

Pruébalo y me cuentas.

Edito: En sí, el puerto 25, es el puerto de transmisión SMTP sin seguridad (como se hacía antes), y es la forma de conectarse también al servidor, a través de telnet.

IANA Service Port Numbers List

pues resulta que este servidor de correo también usa el puerto 465 con el 25 no va tampoco. sabeis algun servidor de correo gratuito con el el que funcione

Me parece muy extraño que no funcione con el 25, ya que yo he conseguido conectarme a ese servidor, por una consola telnet. Lo que no he probado, es enviar un mail, ya que al no tener una cuenta de correo en el servidor, no puedo hacer un login.

Intenta seguir los pasos de envio desde una consola telnet desde el ordenador, a ver que pasa.

Porque no pruebas desde tu cliente de correos en Windows y luego miras la opción de debugging que te muestra toda la conversación entres servidores y podras ver que puertos usa, y toda la secuencia de login.

me pierdo en lo que as dicho podrías explicar un poco mas detallado
muchas gracias

Vas a tu cliente de windows (outlook, o el que uses) y envias un email, ves que esta todo okay.
Luego habiltas el loggeo de esta forma

Manu86, mira los mensajes privados, porque estamos cerca de la solucion.

Para quien no entienda esto, el caso es que por mensaje privado, hemos mantenido una conversación con "información sensible" (contraseñas de las cuentas de mail) y parece que hay algún problema con alguna contraseña, ya que con otra cuenta de correo del mismo servidor, el código funciona a la perfección.

Yo intenté hacer un login manual desde una consola telnet, pero parece ser que, el tiempo que tardo en copiar y pegar el usuario y el password, es suficiente como para que de un timeout (supongo que por seguridad) y no dejarte logarte. El arduino, no pierde ese tiempo, de forma que consigue logarse, y enviar el email.

Buenas, me comentas por mensaje privado que te da un error de conexión. Te contesto por aqui, porque toda la información que quede publicada, le puede servir a más gente.

OK, he hecho pruebas, y ese error tiene que ser, o porque el arduino no consigue salir al exterior, o porque no consigue resolver el nombre DNS. Lo del DNS, lo podríamos corregir cambiando el nombre de host por la IP del host, pero eso tiene un problema, y es que si el proveedor cambia la IP, el arduino no enviará mails, de forma que vamos a intentar no tocar esta parte.

Otros posibles problemas, son:

-Al switch o al router, no les gusta la mac address que le has puesto al arduino. Este es un problema bastante más habitual de lo que debería. Para comprobar esto, tienes que hacer un ping a la IP del arduino, desde un ordenador que esté conectado a la misma red. Si no responde al ping, ya sabemos cual es el problema, de forma que, tendremos que usar una MAC que le guste al switch o al router. Una posibilidad, es usar un vendor de un dispositivo que funciona en la red, es decir, si tenemos conectado un PC que funciona perfectamente, copiamos los 3 primero numeros hex de su mac, y los usamos en la mac del arduino (en los 3 primeros también), pero cuidado con esto. Si después de hacer esto, tenemos un PC en la red que deja de funcionar su conexion de red, es que hemos duplicado su mac sin querer. Es dificil que pase, pero puede pasar.

-Las pruebas se hacen en una red corporativa (de una empresa) y tienen algún tipo de firewall, que por seguridad, solo abre los puertos necesarios, de forma que el puerto 25, está cerrado y no conseguimos que el arduino se comunique por ese puerto. En este caso, habría que hablar con el administrador de esa red, para ver la posibilidad de abrir ese puerto, aunque solo sea para la red del arduino.

De momento, prueba este código:

#include <SPI.h>
#include <Ethernet.h>
 
// this must be unique
byte mac[] = { 0x00, 0x0C, 0x41, 0x00, 0x59, 0x67 };  
// change network settings to yours
IPAddress ip( 192, 168, 1, 55 );    
IPAddress gateway( 192, 168, 1, 1 );
IPAddress dnsserver( 192, 168, 1, 1 );
IPAddress subnet( 255, 255, 255, 0 );
 
char server[] = "send.one.com";
int port = 25 ;
 
EthernetClient client;
 
void setup()
{
  Serial.begin(9600);
  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);
  Ethernet.begin(mac, ip, dnsserver, gateway, subnet);
  delay(2000);
  Serial.println(F("Ready. Press 'e' to send."));
}
 
void loop()
{
  byte inChar;
 
  inChar = Serial.read();
 
  if(inChar == 'e')
  {
      if(sendEmail()) Serial.println(F("Email sent"));
      else Serial.println(F("Email failed"));
  }
}
 
byte sendEmail()
{
  byte thisByte = 0;
  byte respCode;
 
  if(client.connect(server,port) == 1) {
    Serial.println(F("connected"));
  } else {
    Serial.println(F("connection failed"));
    return 0;
  }
 
  if(!eRcv()) return 0;
 
  Serial.println(F("Sending hello"));
  client.println("EHLO send.one.com");
  if(!eRcv()) return 0;
 
  Serial.println(F("Sending auth login"));
  client.println("auth login");
  if(!eRcv()) return 0;
 
  Serial.println(F("Sending User"));//direcion en base 64
// Change to your base64 encoded user
  client.println("xxxxxxxxxxxxxxxx");
 
  if(!eRcv()) return 0;
 
  Serial.println(F("Sending Password"));
// change to your base64 encoded password
  client.println("xxxxxxxxxxxxxxxx");//clave en base 64
 
  if(!eRcv()) return 0;
 
// change to your email address (sender)
  Serial.println(F("Sending From"));
  client.println("MAIL From: <xxx@xxx.com>");///////////
  if(!eRcv()) return 0;
 
// change to recipient address
  Serial.println(F("Sending To"));
  client.println("RCPT To: <yyy@yyy.com>");
  if(!eRcv()) return 0;
 
  Serial.println(F("Sending DATA"));
  client.println("DATA");
  if(!eRcv()) return 0;
 
  Serial.println(F("Sending email"));
 
// change to recipient address
  client.println("To: You <yyy@yyy.com>");
 
// change to your address
  client.println("From: Me <xxx@xxx.com>");
 
  client.println("Subject: Arduino email test\r\n");
 
  client.println("This is from my Arduino!");
 
  client.println(".");
 
  if(!eRcv()) return 0;
 
  Serial.println(F("Sending QUIT"));
  client.println("QUIT");
  if(!eRcv()) return 0;
 
  client.stop();
 
  Serial.println(F("disconnected"));
 
  return 1;
}
 
byte eRcv()
{
  byte respCode;
  byte thisByte;
  int loopCount = 0;
 
  while(!client.available()) {
    delay(1);
    loopCount++;
 
    // if nothing received for 10 seconds, timeout
    if(loopCount > 10000) {
      client.stop();
      Serial.println(F("\r\nTimeout"));
      return 0;
    }
  }
 
  respCode = client.peek();
 
  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  }
 
  if(respCode >= '4')
  {
    efail();
    return 0;  
  }
 
  return 1;
}
 
 
void efail()
{
  byte thisByte = 0;
  int loopCount = 0;
 
  client.println(F("QUIT"));
 
  while(!client.available()) {
    delay(1);
    loopCount++;
 
    // if nothing received for 10 seconds, timeout
    if(loopCount > 10000) {
      client.stop();
      Serial.println(F("\r\nTimeout"));
      return;
    }
  }
 
  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  }
 
  client.stop();
 
  Serial.println(F("disconnected"));
}

Por razones de seguridad, he quitado las direcciones de mail y los usuarios y contraseñas, que los tendras que añadir tu. Le he puesto una mac con vendor Linksys y he separado el DNS, por si algún día se quiere hacer algún cambio. Si esto no funciona, hay que empezar a pensar en lo comentado más arriba sobre el firewall.

se ve que conmigo no quiere mandar email la cosa es que si intento hacer un ping a la dirección send.one.com
me da tiempo de espera agotado para esa solicitud nose si tiene algo que ver.