Read POP3 Mails

Hi,

I want te read mails existing in an pop3 mail account. My Arduino Uno and Ethernetshield2 connect with the Mailbox, but I don´t get the text of the mail. Can anyone tell me my error.

Only anonymous data are sent in the mails so I can use port 110

Here´s my Code:

#include <SPI.h>
#include <Ethernet2.h>

// Use comments to enable or disable this define for debug messages
#define DEBUG_POP

// Use comments to enable or disable the deleting of the mail
//#define ENABLE_DELETE_POP

// The mac address must be an unique number
// A mac generator is used:
// MAC Address Generator
byte mac[] = { 0x90, 0xA2, 0xDA, 0x10, 0x50, 0x93 };
// change network settings to yours
IPAddress ip( 192, 168, X, XX );
IPAddress gateway( 192, 168, X, X );
IPAddress subnet( 255, 255, 255, 0 );

const char pop_server[] = "pop.smart-mail.de";
const int pop_port = 110;
const char pop_user[] = "XXXXXXXX@smart-mail.de"; //mail address hidden
const char pop_pass[] = "XXXXXXXXXX"; //password hidden

#define POP_TIMEOUT 10
#define POP_TIMEOUT_DEFAULT 1000

EthernetClient client;

void setup()
{
Serial.begin( 9600);
Serial.println(F( "\nArduino POP3 email reader"));

if ( Ethernet.begin( mac) == 0)
{
Serial.println("Failed to configure Ethernet using DHCP.");
// no point in carrying on, so do nothing forevermore:
while (1);
}

// print your local IP address.
Serial.println(F( "Ethernet started."));
Serial.print(F( "Local IP = "));
Serial.println(Ethernet.localIP());
Serial.println(F( "Press 'c' to check mail."));
}

void loop()
{
// Create a buffer to receive the commands in (that is the Subject of the mail).
char buffer[32];

byte inChar = Serial.read();
if (inChar == 'c')
{
int n = getEmail( buffer, sizeof(buffer));

if ( n < 0)
{
Serial.print(F("Email POP3 failed, error = "));
Serial.println( n);
}
else
{
if ( n == 0)
{
Serial.println(F("Ready, nothing to do."));
}
else
{
// 'n' is > 0, a command received.
Serial.print(F("Email checked, Command = ""));
Serial.print( buffer);
Serial.println(F("""));
}
}
}
}

// getEmail

int getEmail( char *pBuf, int nBufSize)
{
// nBytes is the number of bytes that is returned by getEmail.
int nBytes = 0;

int nError = client.connect( pop_server, pop_port);

if ( nError == 0)
return ( -200);

// Only a value of 1 is okay.
if ( nError != 1)
return ( nError);

#ifdef DEBUG_POP
Serial.println(F("connected"));
#endif

// The server should respond with "+OK" and maybe more text after that.
// Check if "+OK" can be read.
// The parameter 'true' is to read also everything after the "+OK".
if (!readOk( true))
return -102;

#ifdef DEBUG_POP
Serial.println(F("command USER"));
#endif
client.print(F( "USER "));
client.println( pop_user);
if (!readOk( true))
return -103;

#ifdef DEBUG_POP
Serial.println(F("command PASS"));
#endif
client.print(F( "PASS "));
client.println( pop_pass);
if (!readOk( true))
return -104;

#ifdef DEBUG_POP
Serial.println(F("command STAT"));
#endif
client.println(F( "STAT"));
if (!readOk( false))
return -105;

// The whole line was like this: "+OK 3 15343"
// It means that 3 emails are waiting with a total size of 15343.
// At this moment, the "+OK" is read, but nothing else.
// Check if there is a space after "+OK".
char c = client.read();
if ( c != ' ')
return -106;

client.setTimeout( POP_TIMEOUT); // set timeout lower for parseInt
// Read the number of emails that are on the server.
int nMails = client.parseInt();
client.setTimeout( POP_TIMEOUT_DEFAULT); // restore timeout to 1 second

// Read the remaining of the response to STAT.
readRemaining();

#ifdef DEBUG_POP
Serial.print(F( "Number of emails="));
Serial.println( nMails);
#endif

// Test if there are emails waiting.
if ( nMails == 0)
{
// No emails, but no error. Set buffer to empty string.
nBytes = 0; // the returned value
pBuf[0] = '\0'; // set empty string
}
else if ( nMails > 0)
{
// emails are waiting.
// Scan the emails until the first is found with the keyword "ARDUINO " at the
// beginning of the "Subject: ".

boolean found_and_ready = false;
for ( int nMailNumber = 1; nMailNumber <= nMails && !found_and_ready; nMailNumber++)
{
// The command RETR gets the whole mail.
// The command TOP gets the header plus 'size' of the body.

#ifdef DEBUG_POP
//Serial.print(F( "command RETR 1 ")); //Liest die Mail
Serial.print(F( "command TOP 1 5"));
Serial.print( nMailNumber);
Serial.println(F( " 0")); //******** Evtl. statt 0 höhere Zahl
#endif
// client.print(F( "RETR 1 "));
client.print(F( "TOP 1 5"));
client.print( nMailNumber);
client.println(F( " 0")); //******** Evtl. statt 0 höhere Zahl

// Use readOk with parameter 'false' to stop reading after "+OK".
if (!readOk(false))
return -107;

client.setTimeout( POP_TIMEOUT); // set short timeout for find().
// find() returns true if found and false if not.
boolean foundsubject = true; //client.find( "Subject: ARDUINO");
client.setTimeout( POP_TIMEOUT_DEFAULT); // restore timeout to 1 second

if ( foundsubject)
{
#ifdef DEBUG_POP
Serial.println(F("Found an email for me"));
#endif

int i;
for ( i = 0; i < (nBufSize - 1) && client.available(); i++)
{
char c = client.read();
if (c == '\r' || c == '\n')
break;
pBuf = c;

  • }*
  • // Add zero terminator*
    _ pBuf = '\0';_
    * nBytes = i; // the number of received bytes is returned by the getEmail() function.*
    * // More text of the header could be following the Subject.*
    * // That is read and disregarded.*
    * readRemaining();*
    #ifdef DEBUG_POP
    * Serial.print(F( "Subject = "ARDUINO"));*
    * Serial.print( pBuf);*
    * Serial.println(F( """));*
    #endif
    * //#ifdef ENABLE_DELETE_POP*
    * // Delete the just read message.*
    //#ifdef DEBUG_POP
    * //Serial.print(F( "command DELE "));*
    * Serial.println( nMailNumber);*
    //#endif
    * client.print(F( "DELE "));*
    * client.println( nMailNumber);*
    * if (!readOk( true))*
    * return -108;*
    * //#endif*
    * found_and_ready = true;
    _
    }_
    _
    else*_
    * {*
    #ifdef DEBUG_POP
    * Serial.println(F("No ARDUINO keyword in subject"));*
    #endif
    * readRemaining();*
    * }*
    * }*
    * }*
    #ifdef DEBUG_POP
    * Serial.println(F( "Sending QUIT"));*
    #endif
    * client.println(F( "QUIT"));*
    * if (!readOk( false))*
    * return -109;*
    * client.stop();*
    #ifdef DEBUG_POP
    * Serial.println(F("normally disconnected"));*
    #endif
    * return ( nBytes);*
    }
    // Read the response from the mail server.
    // That is "+OK" if everything is okay.
    // Parameter 'readAll' is to read every character after the "+OK".
    boolean readOk( boolean readAll)
    {
    * int loopCount = 0;*
    * char bufOk[4];*
    * // Wait for response of mail server, with a timout.*
    * while (!client.available())*
    * {*
    * delay(1);*
    * loopCount++;*
    * // if nothing received for 10 seconds, timeout*
    * if (loopCount > 10000)*
    * {*
    * client.stop();*
    #ifdef DEBUG_POP
    * Serial.println(F("\nTimeout"));*
    #endif
    * return false;*
    * }*
    * }*
    * // Read the first three bytes.*
    _ client.readBytes(bufOk, 3); //******** Evtl. statt 0 höhere Zahl_
    #ifdef DEBUG_POP
    _ Serial.write(bufOk, 3); //******** Evtl. statt 0 höhere Zahl_
    * Serial.println();*
    #endif
    * // Is it "+OK" ?*
    * if ( strncmp( bufOk, "+OK", 3) != 0)*
    * {*
    * popFail();*
    * return false;*
    * }*
    * // When the text after "+OK" is not needed, everything*
    * // else can be read and disregarded*
    * // (or shown in the serial monitor during debugging).*
    * if ( readAll)*
    * readRemaining();*
    * return true;*
    }
    void readRemaining()
    {
    * while (client.available())*
    * {*
    * char c = client.read();*
    #ifdef DEBUG_POP_EXTRA
    * Serial.print( c);*
    #endif
    * }*
    * return;*
    }
    void popFail()
    {
    * int loopCount = 0;*
    #ifdef DEBUG_POP
    * Serial.println(F("popFail"));*
    #endif
    * while (!client.available())*
    * {*
    * delay(1);*
    * loopCount++;*
    * // if nothing received for 10 seconds, timeout*
    * if (loopCount > 10000)*
    * {*
    * client.stop();*
    #ifdef DEBUG_POP
    * Serial.println(F("\nTimeout"));*
    #endif
    * return;*
    * }*
    * }*
    * client.stop();*
    #ifdef DEBUG_POP
    * Serial.println(F("disconnected due to fail"));*
    #endif
    }

Maybe the code (and the emails) would be easier to read if they didn't have italics

To post code and/or error messages:

  1. Use CTRL-T in the Arduino IDE to autoformat your complete code.
  2. Paste the complete autoformatted code between code tags (the </> button)
    so that we can easily see and deal with your code.
  3. Paste the complete error message between code tags (the </> button)
    so that we can easily see and deal with your messages.
  4. If you already posted without code tags, you may add the code tags by
    editing your post. Do not change your existing posts in any other way.
    You may make additional posts as needed.

Before posting again, you should read the three locked topics at the top of the Programming Questions forum, and any links to which these posts point.

If your project involves wiring, please provide a schematic and/or a wiring diagram and/or a clear photograph of the wiring.

Good Luck!

You forgot to include the debug output from your sketch which would say what part of the process is failing. If you are not getting debug output, you should add some.

First of all - thanks to the helpers!!!!

This project has no wiring and produces no error Messages. My problem is that I want the text of the mail body and I have no idea to get it.
Because of the limitation of 9000 chars I had to delete most of the comments.

Here´s a revised code:

#include <SPI.h>
#include <Ethernet2.h>
// Use comments to enable or disable this define for debug messages
#define DEBUG_POP

// Use comments to enable or disable the deleting of the mail
#define ENABLE_DELETE_POP
byte mac[] = { 0x90, 0xA2, 0xDA, 0x10, 0x50, 0x93 };
IPAddress ip( 192, 168, 2, 105 );
IPAddress gateway( 192, 168, 2, 1 );
IPAddress subnet( 255, 255, 255, 0 );
// Set the server POP3 address, the port, the user and password.
// The POP3 mail server is something like this:
const char pop_server[] = "smart-mail.de";
const int  pop_port = 110;
const char pop_user[] = "XXXXXXXX@smart-mail.de"; //hidden
const char pop_pass[] = "XXXXXXX";  //hidden
// The number of milliseconds timeout for parseInt() and find().
// The response time for the Server can still be 10 seconds.
#define POP_TIMEOUT 10
#define POP_TIMEOUT_DEFAULT 1000
EthernetClient client;

void setup()
{
  Serial.begin( 9600);
  Serial.println(F( "\nArduino POP3 email reader"));
  // Start Ethernet. Use only the 'mac' parameter for DHCP
  if ( Ethernet.begin( mac) == 0)
  {
    Serial.println("Failed to configure Ethernet using DHCP.");
    // no point in carrying on, so do nothing forevermore:
    while (1);
  }
  // print your local IP address.
  Serial.println(F( "Ethernet started."));
  Serial.print(F( "Local IP = "));
  Serial.println(Ethernet.localIP());
  Serial.println(F( "Press 'c' to check mail."));
}

void loop()
{
  // Create a buffer to receive the commands in (that is the Subject of the mail).
  char buffer[32];
  byte inChar = Serial.read();
  if (inChar == 'c')
  {
    // The getEmail gets the text of the mail Subject into the buffer.
    // The valid number of received characters are returned.
    // If the return value is < 0, it is an error.
    int n = getEmail( buffer, sizeof(buffer));
    if ( n < 0)
    {
      Serial.print(F("Email POP3 failed, error = "));
      Serial.println( n);
    }
    else
    {
      if ( n == 0)
      {
        Serial.println(F("Ready, nothing to do."));
      }
      else
      {
        // 'n' is > 0, a command received.
        Serial.print(F("Email checked, Command = \""));
        Serial.print( buffer);
        Serial.println(F("\""));
      }
    }
  }
}


// getEmail
// --------

int getEmail( char *pBuf, int nBufSize)
{
  // nBytes is the number of bytes that is returned by getEmail.
  int nBytes = 0;

  int nError = client.connect( pop_server, pop_port);

  if ( nError == 0)
    return ( -200);
  // Only a value of 1 is okay.
  if ( nError != 1)
    return ( nError);
#ifdef DEBUG_POP
  Serial.println(F("connected"));
#endif
  // The server should respond with "+OK" and maybe more text after that.
  // Check if "+OK" can be read.
  // The parameter 'true' is to read also everything after the "+OK".
  if (!readOk( true))
    return -102;
#ifdef DEBUG_POP
  Serial.println(F("command USER"));
#endif
  client.print(F( "USER "));
  client.println( pop_user);
  if (!readOk( true))
    return -103;
#ifdef DEBUG_POP
  Serial.println(F("command PASS"));
#endif
  client.print(F( "PASS "));
  client.println( pop_pass);
  if (!readOk( true))
    return -104;
#ifdef DEBUG_POP
  Serial.println(F("command STAT"));
#endif
  client.println(F( "STAT"));
  if (!readOk( false))
    return -105;

  char c = client.read();
  if ( c != ' ')
    return -106;
  client.setTimeout( POP_TIMEOUT);       // set timeout lower for parseInt
  // Read the number of emails that are on the server.
  int nMails = client.parseInt();
  client.setTimeout( POP_TIMEOUT_DEFAULT);  // restore timeout to 1 second
  // Read the remaining of the response to STAT.
  readRemaining();
#ifdef DEBUG_POP
  Serial.print(F( "Number of emails="));
  Serial.println( nMails);
#endif
  // Test if there are emails waiting.
  if ( nMails == 0)
  {
    // No emails, but no error. Set buffer to empty string.
    nBytes = 0;               // the returned value
    pBuf[0] = '\0';           // set empty string
  }
  else if ( nMails > 0)
  {
    // emails are waiting.
    boolean found_and_ready = false;
    for ( int nMailNumber = 1; nMailNumber <= nMails && !found_and_ready; nMailNumber++)
    {
      // The command RETR <x> gets the whole mail.
      // The command TOP <x> <size> gets the header plus 'size' of the body.
#ifdef DEBUG_POP
      Serial.print(F( "command RETR 1 ist "));
      Serial.print( nMailNumber);
      Serial.println(F( "0"));
#endif
      client.print(F( "RETR 1 "));
      client.print( nMailNumber);
      client.println(F( "0"));
      // Use readOk with parameter 'false' to stop reading after "+OK".
      if (!readOk( false))
        return -107;

      client.setTimeout( POP_TIMEOUT);      // set short timeout for find().
      // find() returns true if found and false if not.
      boolean foundsubject = true;    // sonst sucht er nur nach Arduino, kann aber später gut verwendet werden bei Suche nach Buchung   client.find( "Subject: XXXX ");
      client.setTimeout( POP_TIMEOUT_DEFAULT);   // restore timeout to 1 second
      if ( foundsubject)
      {
#ifdef DEBUG_POP
        Serial.println(F("Found an email for me"));
#endif

        int i;
        for ( i = 0; i < (nBufSize - 1) && client.available(); i++)
        {
          char c = client.read();
          if (c == '\r' || c == '\n')
            break;
          pBuf[i] = c;
        }
        // Add zero terminator
        pBuf[i] = '\0';
        nBytes = i;     // the number of received bytes is returned by the getEmail() function.

        readRemaining();
#ifdef DEBUG_POP
        //Serial.print(F( "Subject = \"ARDUINO "));
        Serial.print( pBuf);
        Serial.println(F( "\""));


        found_and_ready = true;
      }
      else
      {
#ifdef DEBUG_POP
        Serial.println(F("No XXXXX keyword in subject"));
#endif

        readRemaining();
      }
    }
  }
#ifdef DEBUG_POP
  Serial.println(F( "Sending QUIT"));
#endif
  client.println(F( "QUIT"));

  if (!readOk( false))
    return -109;
  client.stop();
#ifdef DEBUG_POP
  Serial.println(F("normally disconnected"));
#endif
  return ( nBytes);
}
boolean readOk( boolean readAll)
{

  int loopCount = 0;
  char bufOk[4];
  // Wait for response of mail server, with a timout.
  while (!client.available())
  {
    delay(1);
    loopCount++;
    // if nothing received for 10 seconds, timeout
    if (loopCount > 10000)
    {
      client.stop();
#ifdef DEBUG_POP
      Serial.println(F("\nTimeout"));
#endif
      return false;
    }
  }
  // Read the first three bytes.
  client.readBytes(bufOk, 3);
#ifdef DEBUG_POP
  Serial.write(bufOk, 3);
  Serial.println();
#endif
  if ( strncmp( bufOk, "+OK", 3) != 0)
  {
    popFail();
    return false;
  }
  if ( readAll)
    readRemaining();
  return true;
}
void readRemaining()
{
  while (client.available())
  {
    char c = client.read();
#ifdef DEBUG_POP_EXTRA
    Serial.print( c);
#endif
  }
  return;
}
void popFail()
{
  int loopCount = 0;
  while (!client.available())
  {
    delay(1);
    loopCount++;
    if (loopCount > 10000)
    {
      client.stop();
      return;
    }
  }
  client.stop();

}

My Intention was to get the text of the mail body by sending RETR 1 like in a Telnet session but I only get an +OK.
There is the text the Serial Monitor produces:

Arduino POP3 email reader
Ethernet started.
Local IP = 192.168.2.105
Press 'c' to check mail.
connected
+OK
command USER
+OK
command PASS
+OK
command STAT
+OK
Number of emails=1
command RETR 1 ist 10
+OK
Found an email for me
Sending QUIT
normally disconnected
Ready, nothing to do.

First thing I'd do is get rid of all the #define/#ifdef/#endif statements, and unconditionally print everything that you read from the client. It may be telling you things you need to know.

I don't understand why nMails is 1, but you then try to read #10 of 1.