Email from the core

Hi @MartyMart,

I don’t have to write a fresh email example for you if you wanted to post your code and we could help debug what’s going wrong!

Thanks,
David

Hey Guys,

Found another thread on this as well, so I’ll use that code as a starting point:

Hi @MartyMart,

It looks like you had working email code, and BDub was helping you in this thread: https://community.spark.io/t/tcpclient-connect-with-authentication-to-smtp-server/2538/2

But you had a single bad over the air firmware update? Did you try to flash your code again?

Thanks,
David

Hey Guys,

I’m getting close, still working on this, just making the function a little more robust when handling AUTH with some SMTP servers. :slight_smile:

edit: This isn’t instant you know!
edit 2: Okay, this is weird, I was having problems with the first SMTP server, so I switched, and this one doesn’t want me to say EHLO, etc. So I’m digging in, not gonna give up!

Thanks,
David

Ok David , we are already waiting )))

Okay, here we go! This took me way too long! :slight_smile:

Here’s a nice overview of what SMTP servers expect protocol wise:
http://www.smtp2go.com/articles/smtp-protocol

Make sure you base64 encode your username / password ahead of time (node.js example):

new Buffer("username").toString("base64")
new Buffer("password").toString("base64")

Here’s the Sending Email code I modified based on @jboswell’s code:
https://gist.github.com/dmiddlecamp/8943011

I got this to send me an email, I think we can do a lot of work to improve on this though!

P.S: Be careful when sending emails! Your SMTP server will throttle or ban you if you send too many too fast, or wrongly! Also check your spam folder! :slight_smile:

Thanks,
David

2 Likes

Thank you, David, I’ll get this code and get to work!
Jim

1 Like

This is very neat @Dave – it would have never occurred to me to call SPARK_WAN_Loop() directly. I guess the stack will get untangled eventually.

I did notice that authenticate has three 5 second timeouts in a row before a call to idle() so that could still be a problem.

Also just so everybody knows, not all sendmail programs return the exact same codes for all commands. The RFC has a list, but the best thing might be to telnet into your mail service and do the transaction by hand and see what the response codes are. For instance, my mail server replies with a 350 for the AUTH LOGIN and the rest of the text from the service is base64 encoded until you get the username and password in. In general, the 2xx codes mean success and the 3xx codes mean success so far but please go on. The 4xx codes mean please try again and 5xx codes mean error.

1 Like

Hi @bko,

Totally, just in the event the socket behavior took longer, I wanted to make sure nothing was blocked for long. You’re absolutely right that SMTP servers won’t return exactly the same codes, that would be a great upgrade to this library.

Thanks,
David

Hi Dave,

OK, I must be missing something… I’ve cut and pasted your code into the IDE, but it won’t compile, it gives me the errors below. Maybe I need to open the .cpp file instead of just cut and past of the text? But I can’t figure out how to do that in Spark Build.

So can you point me to somewhere that could help me figure out why I can’t make it work?

Sorry for the Noob-ness!

Thanks!
Jim

the_user_app.cpp:9:22: error: variable or field ‘echoSocketWrite’ declared void
the_user_app.cpp:9:22: error: ‘TCPClient’ was not declared in this scope
the_user_app.cpp:9:37: error: expected primary-expression before 'const’
the_user_app.cpp:10:22: error: variable or field ‘echoSocketWrite’ declared void
the_user_app.cpp:10:22: error: ‘TCPClient’ was not declared in this scope
the_user_app.cpp:10:37: error: ‘String’ was not declared in this scope
the_user_app.cpp:11:20: error: variable or field ‘flushToSerial’ declared void
the_user_app.cpp:11:20: error: ‘TCPClient’ was not declared in this scope
the_user_app.cpp:3:6: error: previous declaration of ‘void setup()’ with ‘C++’ linkage
In file included from …/inc/spark_wiring.h:31:0,
from …/inc/application.h:29,
from the_user_app.cpp:10:
…/inc/spark_utilities.h:116:35: error: conflicts with new declaration with ‘C’ linkage
the_user_app.cpp:4:6: error: previous declaration of ‘void loop()’ with ‘C++’ linkage
In file included from …/inc/spark_wiring.h:31:0,
from …/inc/application.h:29,
from the_user_app.cpp:10:
…/inc/spark_utilities.h:117:34: error: conflicts with new declaration with ‘C’ linkage
the_user_app.cpp: In function ‘void loop()’:
the_user_app.cpp:43:138: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
the_user_app.cpp:43:138: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
the_user_app.cpp:43:138: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
the_user_app.cpp:43:138: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
the_user_app.cpp:43:138: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
the_user_app.cpp:43:138: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
the_user_app.cpp:43:138: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
the_user_app.cpp: In function ‘int SendEmail(char*, char*, char*, char*, char*, char*, char*)’:
the_user_app.cpp:83:101: error: ‘echoSocketWrite’ was not declared in this scope
the_user_app.cpp:85:25: error: ‘flushToSerial’ was not declared in this scope
the_user_app.cpp:101:37: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
the_user_app.cpp:107:37: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
the_user_app.cpp: In function ‘int handshake(char*)’:
the_user_app.cpp:120:25: error: ‘flushToSerial’ was not declared in this scope
the_user_app.cpp:122:37: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
the_user_app.cpp:129:82: error: ‘echoSocketWrite’ was not declared in this scope
the_user_app.cpp:130:37: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
the_user_app.cpp: In function ‘int authenticate(char*, char*)’:
the_user_app.cpp:142:45: error: ‘echoSocketWrite’ was not declared in this scope
the_user_app.cpp:143:33: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
the_user_app.cpp:146:33: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
the_user_app.cpp:149:33: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
the_user_app.cpp: In function ‘void echoSocketWrite(TCPClient, String)’:
the_user_app.cpp:162:19: error: ‘flushToSerial’ was not declared in this scope
the_user_app.cpp: In function ‘int SendEmail(char*, char*, char*, char*, char*, char*, char*)’:
the_user_app.cpp:114:1: warning: control reaches end of non-void function [-Wreturn-type]
make: *** [the_user_app.o] Error 1

Error: Could not compile. Please review your code.

Hi @jimbol,

Ahh sorry about that! Take out this from my code and then it should compile:

#include "application.h"

Thanks!
David

David,
Thanks, it compiles fine now, I’ll see if I can make the next steps!
Jim

1 Like

Hey @MartyMart, would you please do this to your code above:

Thanks!

and @Dave, very nice example! You need to write more examples :smile: I also like the use of the:

void idle() {
    SPARK_WLAN_Loop();
}

I’m sure this would keep the heartbeat up to date, but would it also allow you to receive a flash update OTA?

1 Like

Thanks! It’s a super-rough example. At some point I’ll have to go back and do proper response checking and actually break it into a library and whatnot. :slight_smile:

The general TCP functions of “listen for this kind of response” is something I’d like to build a few more of, since I suspect it’ll go a long way to make it way easier to expand on and write more networking libraries like this.

I’m not 1200% sure, but I think calling “SPARK_WLAN_Loop” will also call “Spark_Communication_Loop”, which should handle stuff like responding to flashing, responding to variable / function requests, etc.

Thanks!
David

So I have had some time to play around tonight, the code works fabulously but I am seeing some strangeness in the serial output. It starts in this section of the code:

Serial.println("sending mail...\n");
echoSocketWrite(client, String("MAIL FROM:<") + String(fromEmail) + String(">") + String("\r\n"));
echoSocketWrite(client, String("RCPT TO:<") + String(toEmail) + String(">") + String("\r\n"));
flushToSerial(client); //client.flush();

The serial output looks good up to there, once it gets past there it starts looking like this:

 2.7.0 Authentication successful
MAIL FROM:<blah@gmail.com>
 2.7.0 AuthenRCPT TO:<blah@gmail.com>
 2.7.0 AuthenDATA
 2.7.0 Authenfrom: blah@gmail.com
 2.7.0 Authento: blah@gmail.com

Notice the ‘2.7.0 Authen’ prefixing all the commands after it, this continues to happen all the way through to the ‘End Data’ I think.

Still going through stuff, mainly just getting the formatting right in putty so I can diagnose the problem via the output. I suppose it’s only semantic at this point because the emails seem pretty solid.

Hi @jboswell,

Awesome! I saw something like this when I was sending mail using Dreamhost’s smtp servers. Hmm, yeah that does seem more like a glitch in my code vs. a weird smtp standard :slight_smile:

Thanks,
David

Hey Jboswell,
I see you’re using gmail, which is what I’m trying to do. I can’t get it to authenticate, I get to the starttls, but can’t get the user and password to get accepted. Can you show me the code that gets you thru the authentication? I’m using the bit below. I’ve tried with and without the extra ehlo, I’ve seen it both ways in different places, and I’ve tried using the Username and password on separate lines as well as separated by a comma, as they are below. Here is also the serial output, maybe that helps. I’ve had to change some of the response blocks to get it to go this far, but I can’t seem to get it to deal with the authentication.

Can you guys see what I’m doing wrong?

Jim

int handshake(char *smtpServer) {
//wait for the server to say something.

flushToSerial(client); //client.flush();
Serial.write("waiting for the server to say hello...\n");
if (blockForResponse("220", 5000) == 0) {
	//handshake failed.
	return 0;
}
idle();

Serial.write("Saying hello back.\n");
echoSocketWrite(client, String("EHLO ") + String(smtpServer) + String("\r\n"));
if (blockForResponse("250", 1250) == 0) {
	//handshake failed.
	return 0;
}
idle();

return 1;

}

int authenticate(char *username, char *password) {
Serial.write(“logging in…\n”);

echoSocketWrite(client, String("starttls") + String("\r\n"));
blockForResponse("220", 5000);

echoSocketWrite(client, String("EHLO") + String("\r\n"));
blockForResponse("2.0.0", 5000);

echoSocketWrite(client, String(username) + String(",") + String(password) + String("\r\n"));
blockForResponse("Ready", 5000);

//echoSocketWrite(client, String(password) + String("\r\n"));
//blockForResponse("Ready", 5000);
 
idle();
return 1;

}

here we go…Connected!
waiting for the server to say hello…
220heard response.
Saying hello back.
mx.google.com ESMTP ac5sm8880618pbc.37 - gsmtp
EHLO smtp.gmail.com
mx.google.co250heard response.
logging in…
-mx.google.com at your service, [75.70.130.131]
250-SIZE 35882577
250-8BITMIME
250-STARTTLS
250-ENHANCEDSTATUSCODES
250 CHUNKING
starttls
-mx.google.co220heard response.
2.0.0 Ready to start TLS
EHLO
2.0.0heard response.
Ready 64bit gibberishblahblah,64bitgibberish
Readyheard response.
sending mail…
MAIL FROM:email@gmail.com
RCPT TO:email@dot.com
DATA
from: email@gmail.com
to: email@dot.com
subject: Email from a Core!

Body body body

I see you’re using gmail

I am only sending to a gmail account, I am using a separate smtp service to send out emails. It’s really easy to use, and it’s like 600 emails a day on the free account:

I was using one or two other ones but I had problems with those, can’t remember what the problems were off the top of my head though.

J

Well, thanks for the help, guys. I finally got the email to go, but had to change to a different smtp server to get it done. Now they are going out well, and with no errors after this mornings session. The email I’m sending is going to a growl address, and it notifies my iPhone when the email gets sent, which is the whole purpose of what I’m trying to do, works well.

Next I have to figure out how to use interrupts, then hook this thing up to a battery and see if I can get 8 hours of life out of it!

Thx,
Jim

2 Likes

This is such a great feature, anyone had made this into the Spark library for web Build ?