Sending Emails from the core, locking up!

Trying to send mail from the core. The code below worked fine on an Arduino and a wifi shield, there aren’t any delays in it, not really sure what is going wrong here. It all seems really straightforward, the problem is that I call this function and the core just completely stops responding to any further firmware updates from the web gui. I have to factory reset it after each and every test.

Anyone have any idea’s? I saw the other thread and the suggestion was to use a state machine. I haven’t gotten to trying that code yet but that will be the next step in the process. I can’t be the first person needing to send an email right?

void SendMail(char *Subject, char *Body, int Sensor) {
  if (client.connect(smtp,587)) {
    client.println("EHLO kltan");
    client.println("AUTH LOGIN");
    client.println("username=");  
    client.println("password="); 
    client.println("MAIL FROM:<blah@gmail.com>");   
    client.println("RCPT TO:<blah@gmail.com>");
    client.println("DATA");
    client.println("from:blah@gmail.com");
    client.println("to:asdf@gmail.com");
    client.print("SUBJECT: ");
    client.println(Subject);
    client.println();
    client.print(Body);
    client.println(Sensor);
    client.println(".");
    client.println(".");
    client.println("QUIT");
  }
  if (client.available()) {
    char c = client.read();
  }
  client.flush();
  client.stop();
}
1 Like

Not sure about how what you have will work. Let’s see the rest of your code :smile:

Not a problem, here you go.

long lastUp = 0;

int SenseDelay = 20000;

byte smtp[] = { 46, 105, 158, 236 };  //mailjet SMTP server

//int SensorValue = A0;
int SensorValue = 200; //filler value so I dont have to wait on a sensor

TCPClient client;

void setup() {
    pinMode(SensorValue, INPUT);
}

void loop() {                
    if (millis() - lastUp > SenseDelay) {
        if (analogRead(SensorValue) > 300) {
            char SubjectString[] = "Sensor Check";
            char Body1String[]   = "Values in range!";
            SendMail(SubjectString, Body1String, analogRead(SensorValue));
            lastUp = millis();
        } else if (analogRead(SensorValue) < 300) {
            char SubjectString[] = "Sensor Check";
            char Body1String[]   = "Values out of range!";
            SendMail(SubjectString, Body1String, analogRead(SensorValue));
            lastUp = millis();
        } else {
            Serial.println("Some weird failure.");
            lastUp = millis();
        }
    }
}

void SendMail(char *Subject, char *Body, int Sensor) {
	if (client.connect(smtp,587)) {	//Successful connection to SMTP Server
		client.println("EHLO kltan");
		client.println("AUTH LOGIN");
		client.println("username=");
		client.println("password=");
		client.println("MAIL FROM:<blah@gmail.com>");   
		client.println("RCPT TO:<blah@gmail.com>");
		client.println("DATA");
		client.println("from:blah@gmail.com");
		client.println("to:asdf@gmail.com");
		client.print("SUBJECT: ");
		client.println(Subject);
		client.println();
		client.print(Body);
		client.println(Sensor);
		client.println(".");
		client.println(".");
		client.println("QUIT");
	} else {}	//SMTP Server Connection failed
	
	if (client.available()) {
		char c = client.read();
	}
	
	//Disconnecting from the SMTP server.
	client.flush();
	client.stop();
}

Aha, here's your problem... 20 second hard delay :wink: Please see my post here on the same topic with the same problem:

1 Like

That’s not a delay though, that’s just a simple math operation that executes code inside every time millis - lastUp is greater than 20000 milliseconds. Main continues to loop until that returns true, then it dives into the second block of code (the else if). That is of course all dependent upon my understanding of how that bit of logic actually functions, and maybe I am utterly wrong, but I don’t think I am?

No delay there, this program runs fine if I am not calling that SendMail function. I can turn LED’s on and off just fine without perma-locking my core, the second I call that function is when everything hits the fan.

J

Hi @jboswell

In general, you are not checking any of the responses from the mail server, maybe that’s an area to explore? Have your tried doing the sendmail steps by hand by telneting to port 587 on your mailhost? Maybe something has changed there, like requiring STARTTLS.

I would definitely change the read loop to be more like this:

int bytecount = client.available();
while (bytecount>0) {
        char c = client.read();
        bytecount--;
} 

There was/is a bug where calling available() twice without reading all the bytes was causing problems. I don’t know where the fix is in the current web IDE, but I know that several folks said the fix worked for them.

I would also move the client.flush() call up to right after the client.println(“QUIT”);

1 Like

Wow, sorry… I’m trying to do too much today and not focusing very well! Yeah you’re fine on delays. My bad.

Hey @bko,

It’s like you are reading my mind, I was just telnetting in and checking everything. I found something weird already, when I put in the first command after connecting it fails and then I type it in again and it succeeds. It looks like almost anything I type in first fails, I have to go check another smtp server to confirm but it’s strange because I have an arduino with a wifi shield that is happily sending out mails with the exact same code.

I tried doubling the first line (EHLO kltan) and the core still locked up, going to try another smtp relay but what I would really like is a server that I can tail the logs on and see the commands getting issued. Setting that up is a bit of a pita right now though.

The part I don’t really understand is that client.available() part, I am not exactly sure what it is doing, just catching extra stdout from the mailserver? Not even sure why it needs to do that.

Regarding the error handling on the server commands, yeah, I haven’t added anything for that yet, and it’s looking like now I actually should. Thank you for the help, going to start building that and then check against another relay.

No worries, we all have those days. Thanks for looking at it!

1 Like

My routine works fine is I dont use the AUTH LOGIN part… If I’m on my ISP smtp server, that doesnt require authentication, works A1, if I changed ISP and try to reach my original ISP, it requires SMTP login and there is a failure… where my arduino does it no problem with same code…

The one thing the arduino can do that the spark core currently can’t do, is sit around forever waiting for a routine to finish. It’s possible that the arduino just hangs out a long time, and that same response is hanging up the core. On the arduino, can you put little time stamps in serial prints in various places and see how long things are taking?

void setup() {
  pinMode(D7,OUTPUT);
  digitalWrite(D7,HIGH);
  Serial.begin(115200);           // set up Serial library at 9600 bps
  while(!Serial.available());  // wait for ENTER to be pressed after opening serial monitor
  digitalWrite(D7,LOW);
}

void loop() {
uint32_t start = millis();
// FIRST OPERATION
Serial.print("1st operation done at: "); Serial.print.ln(millis() - start);

// SECOND OPERATION
Serial.print("2nd operation done at: "); Serial.print.ln(millis() - start);

// LAST OPERATION
Serial.print("Last operation done at: "); Serial.print.ln(millis() - start);
}

Optionally you could just do the LAST operation first, and see how long the total loop is taking… better be less than 10 seconds :wink:

1 Like

Optionally you could just do the LAST operation first, and see how long the total loop is taking... better be less than 10 seconds wink

Hrm, that's a concern. Does the Core drop completely offline or just disconnect from the cloud when a function takes longer than 10 seconds to complete?

I haven't hooked the core up via USB really, just piped voltage in via a power source and wrote code on the web CLI. I am not really sure how to get serial out of it, putty maybe? I am going to sort that out tonight.

J

Check out this thread, even if you don't have windows it should help. Sounds like you might though.

Typically it drops back to trying to connect to WLAN if I remember correctly... then NET, then CLOUD.

Ok, well, got a few things working and a little bit closer to the source of the problem, I think. Thank you guys for all your help and input, definitely wouldn’t have gotten anywhere even close to where I am without it!

So, here’s where I am at… I got the core hooked up via USB and I can putty in and see all the serial print stuff (yaaaay), then I compared some code to the arduino playground email code and grabbed a little function that reads the output and prints it back to the serial monitor. Finally I also added in the timer above to measure the length of time I am sitting in the SendMail function (whew). Now I am seeing a “Timeout” in the middle of that routine - it gets as far as this line:

client.println("DATA");

It starts timing out there fairly consistently, the problem is that it times out WELL before 10 seconds, so I am guessing this isn’t a hard and fast rule. I guess my next step would be to pull down the code and modify the timeout values?

Anyway, here is the current code:

uint32_t counter = 0;

long lastUp = 0;

int SenseDelay = 10000;

byte smtp[] = { 46, 105, 158, 236 };  //mailjet SMTP server

//int SensorValue = A0;
int SensorValue = 200;


TCPClient client;

void setup() {
    pinMode(D7, OUTPUT);         // Turn on the D7 led so we know it's time
    digitalWrite(D7, HIGH);      // to open the Serial Terminal.
    Serial.begin(9600);         // Open serial over USB.
    while(!Serial.available()); // Wait here until the user presses ENTER in the Serial Terminal
    digitalWrite(D7, LOW); // Turn off the D7 led ... your serial is serializing!
    pinMode(SensorValue,INPUT);
}

void loop() {                
    if (millis() - lastUp > SenseDelay) {
        if (analogRead(SensorValue) > 300) {
            char SubjectString[] = "Sensor Check";
            char Body1String[]   = "Values in range!";
            SendMail(SubjectString, Body1String, analogRead(SensorValue));
            lastUp = millis();
        } else if (analogRead(SensorValue) < 300) {
            char SubjectString[] = "Sensor Check";
            char Body1String[]   = "Values out of range!";
            SendMail(SubjectString, Body1String, analogRead(SensorValue));
            lastUp = millis();
        } else {
            Serial.println("Some weird failure.");
            lastUp = millis();
        }
    }
}

void SendMail(char *Subject, char *Body, int Sensor) {
	if (client.connect(smtp,587)) {	//Successful connection to SMTP Server
	uint32_t start = millis();
	Serial.print("1st operation done at: "); Serial.print.ln(millis() - start / 1000);
		client.println("EHLO kltan");
		if(!eRcv());
		Serial.println();
		client.println("AUTH LOGIN");
		if(!eRcv());
		Serial.println();
		client.println("username=");
		if(!eRcv());
		Serial.println();
		client.println("password=");
		if(!eRcv());
		Serial.println();
		client.println("MAIL FROM:<blah@gmail.com>");   
		if(!eRcv());
		Serial.println();
		client.println("RCPT TO:<blah@gmail.com>");
		if(!eRcv());
		Serial.println();
		client.println("DATA");
		if(!eRcv());
		Serial.println();
		Serial.print("Last operation done at: "); Serial.print.ln(millis() - start / 1000);
		Serial.println();
		client.println("from:blah@gmail.com");
        if(!eRcv());
		Serial.println();
		/*client.println("to:blah@gmail.com");
		if(!eRcv());
		Serial.println();
		client.print("SUBJECT: ");
		if(!eRcv());
		Serial.println();
		client.println(Subject);
		if(!eRcv());
		Serial.println();
		client.print(Body);
		if(!eRcv());
		Serial.println();
		client.println(Sensor);
    	if(!eRcv());
		Serial.println();
		client.println(".");
		if(!eRcv());
		Serial.println();
		client.println(".");
		if(!eRcv());
		Serial.println();
		client.println("QUIT");
        if(!eRcv());
		Serial.println();
		*/
		client.flush();
	} else {}	//SMTP Server Connection failed
	/*int bytecount = client.available();
    while (bytecount>0) {
        char c = client.read();
        bytecount--;
    }*/
	
	//Disconnecting from the SMTP server.
	client.stop();
}

byte eRcv() {
    byte respCode;
    byte thisByte;
    char c;
    int loopCount = 0;

    while(!client.available()) {
        delay(1);
        loopCount++;
        // if nothing received for 500ms, timeout
        if(loopCount > 2000) {
            client.stop();
            Serial.println("\r\nTimeout");
            return 0;
        }
    }

    respCode = client.peek();
    while(client.available()) {  
        c = client.read();    
        Serial.print(c);
    }

    if(respCode >= '4') {
        return 0;  
    }
    return 1;
}

I have unfortunately run out of time right now and the web gui is acting funky now for some reason when I factory reset the core now - won’t let me select my core in the gui for some weird reason. Good time to hit the hay, will hopefully be able to make further progress tomorrow.

Hi @jboswell

This code looks like a good start! I did want to point out that the comments and code don’t really match in your eRcv function. The comment says there is a 500ms timeout but the code counts to 2000 with a delay(1) in the loop for a total potential max delay of 2 seconds.

There are 6 callers of eRcv() before the client.println(“DATA”) call for a total potential delay of 12 seconds possible. The Serial.println(); calls at 9600 baud are taking some time too, I am sure.

I would try to rewrite your code so that you handle one exchange with the SMTP server per time around loop(), like a big state machine. I don’t know much about the mailjet service, but SMTP in general is not a quick service.

Hey Guys,

It’s like everyone on the forum wants to send email from a core this morning!

If it’s okay I thought I’d pick up where @jboswell and @bko left off and try to get that smtp code working reliably. I’ll post my results when it’s all up and running. :smile:

Thanks,
David

1 Like

The more the merrier, email notifications are somewhat critical to pretty much all the projects I am working on.

1 Like

Sending a email when sensors are triggered would be awesome!

Looking froward to seeing this working.

Okay, dove into this a bit, mostly I modified the code to also output everything to serial, and I added some very basic logic to wait for a particular status code back from the server before proceeding. It sent me a few (not properly formatted emails), but it sent an email!

1 Like

It's.... so beautiful......

Dave, you are amazing dude, it's going to take me some time just to go through all that amazing code to wrap my head around half of it is going to take a couple days I think. Gonna paste it in and try and get it working out of the box real quick and take it from there.

You rock dude!

2 Likes