Anybody seen an email client built upon the Arduino WiFi shield?

Any success stories out there?

This is for the ethernet shield, but the transport should be easy to convert. Set up the Wifi instead of the ethernet shield in setup. The rest should be the same.
http://playground.arduino.cc/Code/Email

I'm clearly in over my head in this area. I modified the code and the shield does link, but after I enter the 'e' to send, I get 'connection failed' followed by the expected 'Email failed'. I've looked over the various WiFi*.h files and see no place where to enter the 'critical' MAC address. So I went back to my official WiFi shield packaging and verified my actual MAC address. It doesn't work as a value in the WiFi.begin statement. When I compile that, I get "no matching function for call to "WiFiClass::begin(char[7].......message.

Here is my modified code.

/*
    Email client sketch for IDE v1.0.1 and w5100/w5200
    Posted December 2012 by SurferTim
 */
 
#include <SPI.h>
#include <WiFi.h>
 
 
char ssid[] = "MYSSID";      //  your network SSID (name) 
char pass[] = "FFFF2088FFFF383FFFF0D8501";   // your network password
int keyIndex = 1;                 // your network key Index number (needed only for WEP)
 
// this must be unique
 byte mac[] = { 0x90, 0xA2, 0xDA, 0xFF, 0xFF, 0xFF };  
 // change network settings to yours
 IPAddress ip( 192, 168, 1, 12 );    
 IPAddress gateway( 192, 168, 1, 1 );
 IPAddress subnet( 255, 255, 255, 0 );
 
// change server to your email server ip or domain
 // IPAddress server( 1, 2, 3, 4 );
 char server[] = "email.?????.com";

int status = WL_IDLE_STATUS;
// WiFiServer server(80); 

WiFiClient client;

void setup()
 {
   Serial.begin(9600);
   pinMode(4,OUTPUT);
   digitalWrite(4,HIGH);
   WiFi.begin(ssid, keyIndex, pass, mac); 
  delay(2000);
   Serial.println("Ready. Press 'e' to send.");
 }
 
void loop()
 {
   byte inChar;
 
  inChar = Serial.read();
 
  if(inChar == 'e')
   {
       if(sendEmail()) Serial.println("Email sent");
       else Serial.println("Email failed");
   }
 }
 
byte sendEmail()
 {
   byte thisByte = 0;
   byte respCode;
 
  if(client.connect(server,25)) {
     Serial.println("connected");
   } else {
     Serial.println("connection failed");
     return 0;
   }
 
  if(!eRcv()) return 0;
   Serial.println("Sending helo");
 
// change to your public ip
   client.write("helo 1.2.3.4\r\n");
 
  if(!eRcv()) return 0;
   Serial.println("Sending From");
 
// change to your email address (sender)
   client.write("MAIL From: <me@mydomain.com>\r\n");
 
  if(!eRcv()) return 0;
 
// change to recipient address
   Serial.println("Sending To");
   client.write("RCPT To: <you@yourdomain.com>\r\n");
 
  if(!eRcv()) return 0;
 
  Serial.println("Sending DATA");
   client.write("DATA\r\n");
 
  if(!eRcv()) return 0;
 
  Serial.println("Sending email");
 
// change to recipient address
   client.write("To: You <you@yourdomain.com>\r\n");
 
// change to your address
   client.write("From: Me <me@mydomain.com>\r\n");
 
  client.write("Subject: Arduino email test\r\n");
 
  client.write("This is from my Arduino!\r\n");
 
  client.write(".\r\n");
 
  if(!eRcv()) return 0;
 
  Serial.println("Sending QUIT");
   client.write("QUIT\r\n");
 
  if(!eRcv()) return 0;
 
  client.stop();
 
  Serial.println("disconnected");
 
  return 1;
 }
 
byte eRcv()
 {
   byte respCode;
   byte thisByte;
 
  while(!client.available()) delay(1);
 
  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;
 
  client.write("QUIT\r\n");
 
  while(!client.available()) delay(1);
 
  while(client.available())
   {  
     thisByte = client.read();    
     Serial.write(thisByte);
   }
 
  client.stop();
 
  Serial.println("disconnected");
 
}

There could be a couple reasons for that fail.

The first is this function returns a value.

 WiFi.begin(ssid, keyIndex, pass, mac);

You do not know if it connected to the wireless network to provide the transport. And I see no parameter for sending a mac address in the Wifi.begin() function.

The second is the email server ip or domain. Are you sure that is correct?

Right, no place to put the MAC address. No place in WiFi.h, or any of the other .h's that are used. If I pull the ,mac out of that statement and replace the bogus 128bit WEP password with the real one, and the put the real MAC address in there, it never connects. The WiFi shield works fine in other sketches, none of which require the MAC address. I used my real email server address and still it says: connection failed followed by email failed.

What is this function returning?

   WiFi.begin(ssid, keyIndex, pass);

Returns
WL_CONNECTED when connected to a network
WL_IDLE_STATUS when not connected to a network, but powered on

Are you certain you have the correct email server for that domain? I use nslookup to find that.

From a command prompt

nslookup
set query=mx
mydomain.com

It should return a MX preference mail exchanger ip for mydomain.com.

This is what shows up when I run nslookup.

C:\Windows\system32>nslookup
1.1.168.192
primary name server = localhost
responsible mail addr = nobody.invalid
serial = 1
refresh = 600 (10 mins)
retry = 1200 (20 mins)
expire = 604800 ( 7 days)
default TTL = 10800 ( 3 hours)
Default Server: UnKnown
Address: 192.168.1.1

I plugged 'localhost' into the char server[] = statement - no difference.

If the MAC address is critical to make it out of my LAN, I'm not seeing anyplace to use it.

Then your dns setting in your network settings is not correct. Mine shows the dns server I entered in my network settings. It should not be localhost.

Doesn't the 'gateway' 192.168.1.1' provide me with the 'autoconfiguration = yes' info? I'm able to send and receive emails, from my other wireless devices.

Doh! I totally missed the complete mx query. So after I corrected that char server[] statement. Now I get this message.

Ready. Press 'e' to send.
connected
554 mail4c40.carrierzone.com ESMTP commands out of sync
500 5.5.1 Command unrecognized: ""
500 5.5.1 Command unrecognized: ""
disconnected
Email failed

There are 3 entries for the mx query.

Error 554 is commonly associated with a blacklist of certain sending ip addresses.

I wonder if the "MAC Address" not being present is tossing the shield into a generic blob. Like I said, no problems with other wireless devices emailing...
I'll have to try this whole deal out with the Ethernet shield and see whether that works or not. I suspect it'll work just fine. I only need the wireless capability to remotely notify me if the reactor is going critical :wink:

Is this the same settings your computer's email program uses? No user/password required and port 25? Some email servers are fussy about that. Spamhaus is the major spam blocking utility used by email servers. Maybe they show your ip range as a spammer?

This code uses the same protocol as an email server, not a client.

edit: That appears to be a protocol error, not a transport error. I don't think it will matter if it an ethernet shield or WiFi shield.

My SMTP requires authentication (username, password), Address 25, etc. Where does that go in the code?

PS forget the reactor, I want to be alerted when a critter (rabbit, raccoon, neighbor) enters my greenhouse.

Learning:
My SMTP requires authentication (username, password), Address 25, etc. Where does that go in the code?

PS forget the reactor, I want to be alerted when a critter (rabbit, raccoon, neighbor) enters my greenhouse.

It doesn't. That is the difference between client and server exchanges. If you want me to test it, PM me your email address and I will try. It may be a few hours. I'm about to head out for a few beers with a friend.

Even if it were a nuclear reactor, it does not affect the protocol. :slight_smile:

Some code fragments that might be worth a look.

http://www.opinionatedgeek.com/dotnet/tools/base64encode/

  if (client.connect()) {
     Serial.println("connected");

     SendMsg("EHLO " + ServerName); /* say hello*/
     SendMsg("AUTH LOGIN ");
     SendMsg(UserName64); /* Username*/
     SendMsg(Password64); /* Password */
     SendMsg("MAIL From:<" + Sender +">"); /* identify sender */
     SendMsg("RCPT To:<" + Recipient + ">"); /* identify recipient */
     SendMsg("DATA");
     SendMsg("To: " + Recipient); /*  recipient in message header */
     SendMsg("From: " + Sender); /* seder name in message header */
     SendMsg("Subject: "+ Subject); /* insert subject */
     SendMsg(""); /* empty line */
     SendMsg(Body); /* insert body */
     SendMsg(""); /* empty line */
     SendMsg("."); /* end mail */
     SendMsg("QUIT"); /* terminate connection */
     client.println();
  picture=SD.open("picture.jpg",FILE_READ);
  client.connect("smtp.mail.yahoo.com",25);
  client.print("HELO\nAUTH PLAIN\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n");  // x: base64 encoded login: \0foo@yahoo.com\0password
  client.print("MAIL FROM:<foo@yahoo.com>\nRCPT TO:<bar@fakemail.com>\nDATA\nFrom: \"Foo\" <foo@yahoo.com>\r\nTo: bar@fakemail.com\r\nSubject: Picture attached\r\n");
  client.print("Content-Type: image/jpeg; name=\"picture.jpg\"\r\nContent-Disposition: attachment; filename=\"picture.jpg\"\r\nContent-Transfer-Encoding: base64\r\n\r\n");
  encode();
  client.print("\r\n.\r\nQUIT\n");
  client.stop();
  picture.close();

A few beers later, I'm feeling good, and the email was sent. All went well from my Arduino on a commercial ip. It should be in your mailbox. It must be rejecting email from your ip. The response you posted showed it did not even send the "MAIL from" or "RCPT to" fields. It rejected yours on your ip alone. I used mx1c40.carrierzone.com as your email server.

edit: I noticed we used different servers. Try your send again using the server I used.

Well thanks to Tim, we successfully were able to send each other an email. Almost a perfect 10, with a small issue in knowing and using the 'other' guys email server. However, for my requirement to have the "official Arduino WiFi Shield" send me an email from the remote location, this WORKS! You may use the network command NSLOOKUP to find your email server address. If you setup your email and use SMTP, it'll be the SMTP server name. We ran into a issue with the WiFi.h library not using the device MAC address, so some destinations will bounce you immediately as a spammer. (nice). Anyway, if you want to have a good working sketch to try, here you go. Many, many thanks to SurferTim on this one.

/*  THIS ONE WORKS!  Output below is from Serial Monitor
    Ready. Press 'e' to send.
connected
220 mail.yourmailserver.com ESMTP Sendmail 8.13.6/8.13.1; Sun, 17 Mar 2013 12:59:58 +0000
Sending helo
250 mail.yourmailserver.com Hello [38.123.84.242], pleased to meet you
Sending From
250 2.1.0 <me@mine.com>... Sender ok
Sending To
250 2.1.5 <you@mine.com>... Recipient ok
Sending DATA
354 Enter mail, end with "." on a line by itself
Sending email
250 2.0.0 r2HCxwgc027560 Message accepted for delivery
Sending QUIT
221 2.0.0 mail.yourmailserver.com closing connection
disconnected
Email sent

************************************************************************************************************************
*/

//    Email client sketch for IDE v1.0.3 and WiFi Shield
//    Posted December 2012 by SurferTim
//    Modified 17 March by MisterResistor (and SurferTim)
 
 
#include <SPI.h>
#include <WiFi.h>
 
// Setup on a 128 bit WEP network

char ssid[] = "MONKEY";      //  your network SSID (name) 
char pass[] = "C329888B2B00225566778899AA";   // your network password
int keyIndex = 1;                   // your network key Index number (needed only for WEP)
 
IPAddress ip( 192, 168, 1, 12 );    // ipaddress obtained from access point
IPAddress gateway( 192, 168, 1, 1 );
IPAddress subnet( 255, 255, 255, 0 );
 
char server[] = "mail.yourmailserver.com";  // smtp mail server  (mine.com)

int status = WL_IDLE_STATUS;

WiFiClient client;

void setup()
 {
   Serial.begin(9600);
   pinMode(9,OUTPUT);           // changed to use onboard LED
   digitalWrite(9,HIGH);
   WiFi.begin(ssid, keyIndex, pass); 
  delay(2000);
   Serial.println("Ready. Press 'e' to send.");
 }
 
void loop()
 {
   byte inChar;
 
  inChar = Serial.read();
 
  if(inChar == 'e')
   {
       if(sendEmail()) Serial.println("Email sent");
       
       else Serial.println("Email failed");
   }       
 }
 
byte sendEmail()
 {
   byte thisByte = 0;
   byte respCode;
 
  if(client.connect(server,25)) {
     Serial.println("connected");
   } else {
     Serial.println("connection failed");
     return 0;
   }
 
  if(!eRcv()) return 0;
   Serial.println("Sending helo");
 
// change to your public ip
   client.write("helo 1.2.3.4\r\n");
 
  if(!eRcv()) return 0;
   Serial.println("Sending From");
 
// change to your email address (sender)
   client.write("MAIL From: <me@mine.com>\r\n");
 
  if(!eRcv()) return 0;
 
// change to recipient address
   Serial.println("Sending To");
   client.write("RCPT To: <you@mine.com>\r\n");
 
  if(!eRcv()) return 0;
 
  Serial.println("Sending DATA");
   client.write("DATA\r\n");
 
  if(!eRcv()) return 0;
 
  Serial.println("Sending email");
 
// change to recipient address
   client.write("To: You <you@mine.com>\r\n");
 
// change to your address
   client.write("From: Me <me@mine.com>\r\n");
 
  client.write("Subject: Arduino email test\r\n");
 
  client.write("This is from my Arduino WiFi shield!\r\n");
 
  client.write(".\r\n");
 
  if(!eRcv()) return 0;
 
  Serial.println("Sending QUIT");
   client.write("QUIT\r\n");
 
  if(!eRcv()) return 0;
 
  client.stop();
 
  Serial.println("disconnected");
 
  return 1;
 }
 
byte eRcv()
 {
   byte respCode;
   byte thisByte;
 
  while(!client.available()) delay(1);
 
  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;
 
  client.write("QUIT\r\n");
 
  while(!client.available()) delay(1);
 
  while(client.available())
   {  
     thisByte = client.read();    
     Serial.write(thisByte);
   }
 
  client.stop();
 
  Serial.println("disconnected");
 
}

I have just successfully used this code after my own failed attempts. Many thanks for the posting.

Great! I knew someone had to be able to use it. I just need to figure out how to add it to the 'playground' so it doesn't get lost on the forum.

still Learning!