Reading an email.

Hello all. I am trying to see if there is a way to have arduino read an email, parse it for a specific line, and then based on that line perform an action.

example:

blahblahblahblah
blahblahblahblah
lineofinterest in the format of (trigger:action)
blahblahblahblah

effectively, there would be 4 or 5 different actions that may or may not appear in a list (action1, action2, action3) but the trigger at the beginning of the line is always going to be the same.

I have seen many examples of getting the Ethernet shield to check an account and see if there are emails existing, but i have not seen one yet about getting it to actually read the content of an email. any nudge in the right direction would be greatly appreciated

EDIT: So I finally had a chance to sit down and read all your replies and as much as I enjoyed the strings vs array battle that ensued, I think I should clarify my original post. Parsing the email for the line and determining the contents wasn't so much my issue, but I'm glad you all had plenty of opinions on the best way to go about that. I more need a nudge for how to actually get the email stored into the Arduino to be able to read it. I am not very familiar with how Arduino accesses the mailbox and how it can get retrieve the actual email. Once I can get the block of text into the Arduino, I should be good, but I have never tried accessing email from anything but a web browser and I'm not really sure where to start.

Check out this page.

this one may be easier to understand, the example can be found in the Arduino examples

Im trying to simplify this for you myself, but maybe someone else already has a code you can try.

A very poor way of doing it would be to read in a character, store it in a string or array, and using an IF statement, compare it to the word you want.

pseudo:

void loop() {
if(Serial.available())
{
   charData = Serial.read(); //Hi, my name is Andrew

if(charData == ' ' || charData == '\n') // if a space " " is found or a new line is made
{
   if(StringIn == "Andrew"){ //does the string match? :: made an edit from ' ' to " "
      Serial.println("Andrew was found!"); //string does match
      }
   else {
       Serial.println("Andrew was NOT found!"); //string does NOT match
       StringIn = ""; //clear string for new data
       }
     }
 else StringIn += charData; //if string does not equal " ", then store data into string
  } 
}

EDIT: code is now compiled, but not tested. I dont have my stuff with me today, sorry.

Something along the lines of this. I do NOT reccommend this though

Given that you have an Ethernet shield, what you're asking for is possible.

I assume the email would come from a mailbox on the public internet. In that case you would have to set up your network so that the Arduino was able to connect to the public internet.

You would need to find what access protocols the mail server supported, the network ports used (if non-standard) and what authentications standards it supported.

You'd need to write a sketch that used the supported protocols to access and authenticate with the mail server. You may be able to find an existing library for the protocols you use, or you may not. If not, you'd need to create your own implementation. It wouldn't be especially difficult to implement your own, but it wouldn't be trivial either.

You'd need to configure the Arduino with details of the mail server, mailbox address and credentials.

Once you have all that working, you would be able to retrieve emails from the mailbox. The mails could easily be too big for the Arduino to hold in memory so you would probably need to buffer them one line at a time. Your next problem will be to interpret the mail encoding to extract the text. If you only need to support plain text email, no work is needed. If you need to deal with MIME encoded emails then this could be very complicated to implement.

Once you have obtained the text, parsing it to recognise specific key words or patterns would be relatively straight forward, and very similar to examples you'll already find of recognising commands received over the serial port.

What you're asking for would be very much easier to do on a PC since you can use existing software to deal with the networking and protocol handling issues and you could easily implement some pattern matching in JScript, VBScript, or whatever other language you like working in. It's possible on the Arduino, but would require you to find or create quite a bit of functionality.

Even simpler:

void loop() 
{
  if(Serial.available())
  {
     charData = Serial.read(); //Hi, my name is Andrew

       if(charData == ' ' || charData == '\n') // if a space " " is found or a new line is made
       {
           boolean tagged = StringIn.indexOf("Andrew"); //scan string for "Andrew", true if found
           tagged ? Serial.println("Andrew was found!"): Serial.println("Andrew was NOT found!"); //string does it match, or NOT
           StringIn = ""; //clear string for new data
       }
   }
   else StringIn += charData; //if string does not equal " ", then store data into string
}

again, code is compiled, but not tested.

Here is the string equivalent just as a demonstration of how easy it actually is and less prone to errors down the road (I avoided fixing the piss-poor indenting as part of the demonstration):

char StringIn[80];
index i=0;

void loop() {
if(Serial.available())
{
   charData = Serial.read(); //Hi, my name is Andrew

if(charData == ' ' || charData == '\n') // if a space " " is found or a new line is made
{
    char *tagged = strstr(StringIn, "Andrew"); //scan string for "Andrew", true if found
     tagged!=0 ? Serial.println("Andrew was found!"): Serial.println("Andrew was NOT found!"); //string does it match, or NOT
     StringIn[0] = '\0'; //clear string for new data
     i=0;
       }
     }
 else StringIn[i++] = charData; //if string does not equal " ", then store data into string
 }

@tacticalemu

So there ya go, my code uses the String Method and Arrch uses array method.
Now you said you were going to be reading from an email, so you will need to tweak this line a bit "char StringIn[80];" , Im not sure what the maximum size of an array is, but that should not matter if your getting the data and then clear the array.

But both should work.

Update! mine didn't work properly before, but it does now, and Arrch code does not work at the moment.

String stringOne;
char charData, bodyTag;
byte led = 13;

void setup()
{ 
  pinMode(led,OUTPUT);
  Serial.begin(9600);
}

void loop() {
  if(Serial.available())
  {
    charData = Serial.read(); //Hi, my name is Andrew
    if(charData == '.' || charData == ' ' || charData == '\n')
    {
      bodyTag = stringOne.indexOf("on");
      bodyTag >= 0 ? digitalWrite(led, HIGH): digitalWrite(led, LOW);
      stringOne = '\0';
    }

    else {
      stringOne += charData;
    }
  }
}

You may want to look into using TextFinder.h library. Seems to be made to do what you want to do.

Thanks guys, I'll take a more in depth look at all your suggestions over the weekend, and go from there. I'm still kind of new to Arduino so I'm glad you all were able to at least give me a helpful nudge.

HazardsMind:
Update! mine didn't work properly before, but it does now, and Arrch code does not work at the moment.

I didn't make mine to work; I made it as a demonstration of how easy it is to use a string, rather than a String.

So you demonstrated something he couldn't even test, just to show him how the string works? If it doesn't work then how will he know that the Idea even works to begin with.

HazardsMind:
So you demonstrated something he couldn't even test, just to show him how the string works? If it doesn't work then how will he know that the Idea even works to begin with.

Forums are public; the OP isn't the only one who reads this thread. The point was that anybody who looked at your code, then mine, would realize that c style strings aren't these scary things that are severely limited in what they can do. I didn't post code that worked because you didn't. I simply took your code and converted it into a char array to demonstrate that using Strings aren't that much easier.

I'll make sure that the next time you post code, to assume it doesn't work.

I didn't make mine to work; I made it as a demonstration of how easy it is to use a string, rather than a String.

Guess it just goes to show that String wasn't actually the problem. Who would have thought! :wink:

zoomkat:
Guess it just goes to show that String wasn't actually the problem. Who would have thought! :wink:

Never said it was, but why use it when there is (as demonstrated) an easy alternative when it's known to be a habitual issue causer?

Never said it was, but why use it when there is (as demonstrated) an easy alternative when it's known to be a habitual issue causer?

The issue as I understand it, in the two often referenced discussions, is said to possibly occurr in sub routines using Strings where used memory is normally expected to be freed when the sub routine is exited is not released. I have yet to see any issues in simple code using Strings actually be corrected by changing to strings. Read the discussions and form your opinion.

Ok enough about the strings.

This is a working code that uses arrays. If anyone wants to mod this, go ahead.

char StringIn[100];
int found;
char charData;
int i = 0;
int flag;
byte led = 13;


#include<string.h>
void setup()
{ 
  pinMode(led,OUTPUT);
  Serial.begin(9600);
}

void loop() {
  if(Serial.available())
  {
    charData = Serial.read(); //Hi, this is a test and my name is Andrew.

    if(charData =='.' || charData ==' ' || charData ==',' || charData =='\n') // if anyone of these is entered, it will compare it.
    {       
      found = strcmp("Test",StringIn); // compares the test string to the inputted string. NOTE: will return 0 if they are equal!

      if(found == 0) //are they equal?
       {
        Serial.println("got it");
        flag = 0; 
       }

      else 
       {
        if(!flag)
         { 
          Serial.println("Scanning"); //not equal yet
          flag = 1;
         }
      }

      while(i!=0) 
       {
        StringIn[i--] = 0;
       }
    }
    else{
      StringIn[i++] = charData;   
    } 
    delay(20);
  }
}

NOTE: This code will not return anything if the test word is NOT found.

Hi,

Here's another method I've used when searching for keywords in data streaming in via a serially-connected WiFly wifi bee. A function that returns true if a searchstring (passed in searchString) is found in the serial buffer:

// --------------------------------------------------------------------------------------------
// read the WiFLy serial buffer until it's exhausted, looking for searchString
// return TRUE on finding searchString, leaving buffer at next character after
// the located searchString.  Return FALSE if searchString not found in buffer
// Does not retry until timeout, returns once buffer empty.
// Does NOT empty buffer after finding string.
// Parameters:
//   searchString:          the response we're searching for
//
boolean findInWiFlyBuffer(char* searchString) {
  char * ptr = searchString;                                   // iterator for matching
  char thisChar;  

  while(Serial.available() && *ptr) {                          // ends when found, or no more chars in buffer
    thisChar = Serial.read();                                  // IDE likes using a variable rather than direct comparison
    if(thisChar == *ptr) ptr++;                                // move to next searchSring character for comparison
    else ptr = searchString;                                   // back to start of searchString
  } // while
  return *ptr == 0 ? true : false;                             // returns true if comparison got to end of searchString (null char)
}

To test for the text "test" in the serial stream would simply be a call to:

if(findInWiFlyBuffer("test")) {
  // do stuff
}

If you need it to instead return the number of characters read before the string match, that is also easy done with a slight modification. Note that in this method, everything up to the matched string is discarded from the serial buffer but a benefit is there is no need for a static array to be defined.

Cheers ! Geoff

To be of good practical use, the code needs to check the data stream for something special, at which point the data is captured into a string (or what ever) for further evaluation of the string content.

zoomkat:
To be of good practical use, the code needs to check the data stream for something special, at which point the data is captured into a string (or what ever) for further evaluation of the string content.

In which case my function will be perfect - once it's found the keyword you're searching for, the next call to Serial.read() will be at the data you're wanting to interrogate. All without creating any additional data structure to store it in.

That's precisely how I use it.

Geoff

I'm curious as to how the streaming data stream would be searched for more than one data string without being very cumbersome. With a saved data string the typical string search functions would seem to be easier to use (maybe why they were developed).