I want to get emails read from a Hotmail account using an Arduino Uno. Is there a way to do it with SSL or is there a way to disable SSL?
#include <SPI.h>
#include <Ethernet.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:
// http://www.miniwebtool.com/mac-address-generator/
byte mac[] = { 0xDE, 0x36, 0x5F, 0x0A, 0x19, 0x83 };
// change network settings to yours
IPAddress ip(192, 168, 1, 117);
IPAddress gateway(192, 168, 1, 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:
// mail.yourdomain.com, pop.yourdomain.com, pop3.yourdomain.com
// Using PROGMEM for these causes a fail when trying to connect and log in.
const char pop_server[] = "pop3.live.com";
const int pop_port = 995;
const char pop_user[] = "[email protected]";
const char pop_pass[] = "xxxxxx";
// 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"));
pinMode(13, OUTPUT); // the system led is used for testing
// When the Ethernet Shield is used, there is also a SD card connected
// to the SPI bus. Disable the SD card with chip select at pin 4.
pinMode(4, OUTPUT);
digitalWrite(4, HIGH);
// Start Ethernet. Use only the 'mac' parameter for DHCP
// Use 'mac' and 'ip' parameters for static IP address.
// Ethernet.begin( mac, ip);
// Ethernet.begin( mac, ip, gateway, gateway, subnet);
if (Ethernet.begin(mac) == 0)
{
Serial.println("Failed to configure Ethernet using DHCP.");
// no point in carrying on, so do nothing forevermore:
while (1);
}
Ethernet.begin(mac, ip, gateway, gateway, subnet);
// 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("\""));
// Check the commands.
//
// At this moment, a single command 'L' is used to set system led on or off.
// L=1 (set led on)
// L=0 (set led off)
if (buffer[0] == 'L' && buffer[1] == '=')
{
digitalWrite(13, buffer[2] == '0' ? LOW : HIGH);
}
}
}
}
}
// getEmail
// --------
// Find an email on a mail server, using POP3.
// The Subject should start with "ARDUINO " and the text
// after that is copied into pBuf.
//
// The data in pBuf is only valid if the return value is not an error
// (an error is return value less than zero).
//
int getEmail(char *pBuf, int nBufSize)
{
// nBytes is the number of bytes that is returned by getEmail.
int nBytes = 0;
// Connect to server
// client.connect returns '1' if okay, or negative number if error.
// SUCCESS 1
// 0 (error, unknown timeout, perhaps an error in the library)
// TIMED_OUT -1
// INVALID_SERVER -2
// TRUNCATED -3
// INVALID_RESPONSE -4
// -5 (there is no mail server at that IP address and port)
// The string for the server must be a normal string in sram, no PROGMEM allowed.
int nError = client.connect(pop_server, pop_port);
// During testing, a value of zero was sometimes returned.
// This is not according to the documentation and it is an error.
// Therefor the non-error value '0' is turned into a negative number to
// indicate an error.
if (nError == 0)
return(-200);
// Only a value of 1 is okay.
if (nError != 1)
return(nError);
#ifdef DEBUG_POP
Serial.println(F("connected"));
//Serial.println(nError);
#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 <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 TOP "));
Serial.print(nMailNumber);
Serial.println(F(" 0"));
#endif
client.print(F("TOP "));
client.print(nMailNumber);
client.println(F(" 0"));
// Use readOk with parameter 'false' to stop reading after "+OK".
if (!readOk(false))
return -107;
// The header of the email is waiting to be read, use the Stream.find() to look for the Subject.
// The text "Subject: " should be at the beginning of a line, but that is not tested.
// The first found text "Subject: " is assumed to be the real subject.
// I have checked many years of emails, and the text is always "Subject: ", and never "SUBJECT: ".
// At the moment, it is not possible to use the F() macro for Stream.find
// Only the email that starts with "ARDUINO " at the start of the Subject is used.
client.setTimeout(POP_TIMEOUT); // set short timeout for find().
// find() returns true if found and false if not.
boolean foundsubject = 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
// Read the remaining subject (that is the command for the Arduino) into a buffer.
// Every line from the mail server should end with CR + LF,
// but to be sure, both CR and LF are checked.
// Alternative:
// client.readBytesUntil('\r', pBuf, nBufSize);
// The last position in the buffer is reserved for the zero terminator.
// So read data until (nBufSize-1).
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.
// 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
// Everything is okay, the mail is read and deleted.
// Ready for now, don't process the remaining emails.
found_and_ready = true;
}
else
{
#ifdef DEBUG_POP
Serial.println(F("No ARDUINO keyword in subject"));
#endif
// This email has no "Subject: ARDUINO ".
// But the remaining text has still to be read and disregarded.
readRemaining();
}
}
}
#ifdef DEBUG_POP
Serial.println(F("Sending QUIT"));
#endif
client.println(F("QUIT"));
// After "QUIT", the server still respons with "+OK",
// but after that, the connection might get lost.
// So don't read everything after "+OK" (use parameter 'false' for readOk).
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)
{
// Check the response "+OK" from the mail server
// In most cases that is followed by a space and more text, but not always.
// In case of an error the text "-ERR" is received.
int loopCount = 0;
char bufOk[4];
Serial.print("Connected: ");
Serial.println(client.connected());
Serial.print("Client Available: ");
Serial.println(client.available());
// 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
// 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()
{
// This function is called after checking the "+OK".
// It reads everything from the server, until no more text is
// available.
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
}
Output:
Arduino POP3 email reader
Ethernet started.
Local IP = 192.168.1.117
Press 'c' to check mail.
connected
Connected: 1
Client Active: 0
Timeout
Email POP3 failed, error = -102
-
Your title says it's about sending mail, while the code only contains code for receiving mailGerben– Gerben2015年05月13日 14:20:32 +00:00Commented May 13, 2015 at 14:20
1 Answer 1
Hotmail doesn't provide a non-encrypted POP3 service, which would normally run on port 110.
You have no choice but to use the SSL service. However, you can't. Or not easily. SSL is quite a heavy protocol and it is highly doubtful the little Uno is capable of even coming close to being able to work with it.
The Due might have a chance, but again, unlikely.
You would be best off using a computer (server) to check the emails for you and provide a "digest" of information to the Uno instead.
-
A Due certainly has the resources (memory) to do it, though the challenge may be in finding/creating an implementation. Something with networking on board and an existing library might be easier and more cost effective - for example, a raspberry pi (though at the cost of a more delicate writable-filesystem OS installation). The idea of using an additional server as a proxy to help out is a good one though, if the unsecured nature of the communication to/from that server is acceptable.Chris Stratton– Chris Stratton2015年05月13日 16:15:40 +00:00Commented May 13, 2015 at 16:15