Emailing MULTIPLE csv files from with Ethernet Shield [SOLVED]

Greetings;

I have successfully implemented the code below from a an earlier post about Emailing files from Arduino.

/*
  Email client sketch for IDE v1.0.5 and w5100/w5200
  Posted 7 May 2015 by SurferTim
*/



#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>


// this must be unique
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x59, 0x67 };  
// change network settings to yours
IPAddress ip( 192, 168, 2, 2 );    
IPAddress gateway( 192, 168, 2, 1 );
IPAddress subnet( 255, 255, 255, 0 );

char server[] = "mail.smtp2go.com";
int port = 2525;

File myFile;

 
EthernetClient client;

void setup()
{
 Serial.begin(115200);
 pinMode(53,OUTPUT);
 digitalWrite(53,HIGH);
 Ethernet.begin(mac);
 delay(2000);
 Serial.println(F("Ready. Press 'e' to send."));
 Serial.println(Ethernet.localIP());

 if (!SD.begin(53))
  {
   Serial.println("SD initialization failed!");
  }
  else
  {
   Serial.println("SD initialization done.");
  }

 
 
}

void loop()
{
 byte inChar;

 inChar = Serial.read();
 
 if(inChar == 'e')
 {
     if(sendEmail()) Serial.println(F("Email sent"));
     else Serial.println(F("Email failed"));
 }
}


byte sendEmail()
{
 byte thisByte = 0;
 byte respCode;

 if(client.connect(server,port) == 1) {
   Serial.println(F("connected"));
 } else {
   Serial.println(F("connection failed"));
   return 0;
 }

 if(!eRcv()) return 0;

Serial.println(F("Sending hello"));
  // replace 1.2.3.4 with your Arduino's ip
  client.println("EHLO 192.168.10.105");
  if (!eRcv()) return 0;

  //Serial.println(F("Sending auth login"));
  client.println("auth login");
  if (!eRcv()) return 0;

  //Serial.println(F("Sending User"));
  // Change to your base64 encoded user
  client.println(F("User"));
  if (!eRcv()) return 0;

  //Serial.println(F("Sending Password"));
  // change to your base64 encoded password
  client.println(F("PassWord"));
  if (!eRcv()) return 0;

  // change to your email address (sender)
  //Serial.println(F("Sending From"));
  client.println("MAIL From: <user@isp.co>");
  if (!eRcv()) return 0;

  // change to recipient address
  //Serial.println(F("Sending To"));
  client.println("RCPT To: <rec@rec.com>");
  if (!eRcv()) return 0;

  //Serial.println(F("Sending DATA"));
  client.println("DATA");
  if (!eRcv()) return 0;

  //Serial.println(F("Sending email"));

  // change to recipient address
  client.println("To: JR <rec@rec.com>");

  // change to your address
  client.println("From: PumpRoom <sender@isp.com>");

  client.println("Subject: Pump Room Report");
//------------------------------------------------------------------------

 client.write("MIME-Version: 1.0\r\n");
 client.write("Content-Type: Multipart/mixed; boundary=frontier\r\n\r\n");

 client.write("--frontier\r\n");
 client.write("Content-Type: text/plain\r\n\r\n");

 client.write("This is a csv file from Orientes!\r\n");
 
 client.write("--frontier\r\n");
 client.write("Content-Type: text/plain\r\n");
//  client.write("Content-Type: image/jpeg\r\n");
 client.write("Content-Disposition: attachment; filename=poolLog.csv\r\n");

// this is where you would send your file
 int clientCount = 0;
 myFile = SD.open("poolLog.csv");  
 int myint;

 if(myFile)
 {
   while (myFile.available())
   {
     myint = myFile.read();
     client.write(myint);
     Serial.write(myint);
   }
   client.print("\r\n");
   myFile.close();
             
 }
 else {
   Serial.println(F("File open failed"));
 }

//  client.write("This is a test\r\n");

 client.write("--frontier--\r\n");
 client.println(".");

 if(!eRcv()) return 0;

 Serial.println(F("Sending QUIT"));
 client.println("QUIT");
 if(!eRcv()) return 0;

 client.stop();

 Serial.println(F("disconnected"));

 return 1;
}

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

  while (!client.available()) {
    delay(1);
    loopCount++;

    // if nothing received for 10 seconds, timeout
    if (loopCount > 10000) {
      client.stop();
      Serial.println(F("\r\nTimeout"));
      return 0;
    }
  }

  respCode = client.peek();

  while (client.available()) {
    thisByte = client.read();
    Serial.write(thisByte);
  }

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

  return 1;
}


void efail() {
  byte thisByte = 0;
  int loopCount = 0;

  client.println(F("QUIT"));

  while (!client.available()) {
    delay(1);
    loopCount++;

    // if nothing received for 10 seconds, timeout
    if (loopCount > 10000) {
      client.stop();
      Serial.println(F("\r\nTimeout"));
      return;
    }
  }

  while (client.available()) {
    thisByte = client.read();
    Serial.write(thisByte);
  }

  client.stop();

  Serial.println(F("disconnected"));
}

Two Questions:

1- Which part of the code, past "Subject: xxxx" needs to change in order to send file1.csv, followed by file2.csv, followed by...? Reason for asking, smtp2go.com has a limited amount of emails I can send every month, and I don't want to pay for a subscription.

2- Has anything changed with potentially emailing ability, so I can use Gmail?

Cheers;

Google might be your friend or this thread

blh64:
Google might be your friend or this thread

Thanks BLH64,

I'll parse through that link.

Any comments on question 2?

Thanks

Thanks BLH64;

That helped, but there's still a bug.

  client.println("Subject: Pump Room Report");

  //------- Body of EMAIL-----------
  client.write("MIME-Version: 1.0\r\n");
  client.write("Content-Type: Multipart/mixed; boundary=frontier\r\n\r\n");
  client.write("--frontier\r\n");
  client.write("Content-Type: text/plain\r\n\r\n");
  //-------text portion of email------------
  client.print("IP Address: "); client.println(Ethernet.localIP());
  client.print("Date/Time: "); emailClockDisplay();
  client.println("Pool");
  client.print("Pool EC    : "); client.print(ezoReading[eC], 0); client.println(" uS");
  client.print("Pool Temp  : "); client.print(ezoReading[rTD], 1); client.println(" C");
  client.print("Pool pH    : "); client.print(ezoReading[pH], 2); client.println(" pH");
  client.print("Pool Filter: "); client.print(pReading[poolFilter - 8]); client.println(" bar");
  client.print("BalanceTank: "); client.print(pReading[balanceTank - 8]); client.println(" %");

  client.println("House");
  client.print("Rain Tank Level: "); client.print(pReading[rainTank - 8]); client.println(" m3");
  client.print("House Pressure : "); client.print(pReading[houseLine - 8]); client.println(" bar");
  client.print("Recirc Pressure: "); client.print(pReading[recircFilter - 8]); client.println(" bar");
  client.println();
  //-------eof text portion-----------

  //---send file header---
  client.write("--frontier\r\n");
  client.write("Content-Type: text/plain\r\n");
  client.write("Content-Disposition: attachment; filename=poolLog.csv\r\n\r\n");

  int clientCount = 0;  //send file
  poolFile = SD.open("poolLog.csv");
  int myint;
  if (poolFile) {
    while (poolFile.available()) {
      myint = poolFile.read();
      client.write(myint);
      Serial.write(myint);
    }
    client.print("\r\n");
    poolFile.close();
  }
  else Serial.println(F("File open failed"));
  //---send file footer---
  client.write("--frontier--\r\n");
  
//---send file header---
  client.write("--frontier\r\n");
  client.write("Content-Type: text/plain\r\n");
  client.write("Content-Disposition: attachment; filename=houseLog.csv\r\n\r\n");

  clientCount = 0;  //send file
  houseFile = SD.open("houseLog.csv");
  //int myint;
  if (houseFile) {
    while (houseFile.available()) {
      myint = houseFile.read();
      client.write(myint);
      Serial.write(myint);
    }
    client.print("\r\n");
    houseFile.close();
  }
  else Serial.println(F("File open failed"));
  //---send file footer---
  client.write("--frontier--\r\n");
  client.println("."); //---eof email---
  
  
  if (!eRcv()) return 0;

  //Serial.println(F("Sending QUIT"));
  client.println("QUIT");
  if (!eRcv()) return 0;

  client.stop();

  Serial.println(F("disconnected"));
  needToSendEmail = false;    //sent email successfully, no need to send again, until flag is set.
  return 1;
}

The Serial monitor goes through both files, I do get an "email sent" message:

 Email connected
12:49:37.380 -> 220 mail.smtp2go.com ESMTP Exim 4.92-S2G Thu, 25 Jun 2020 17:49:36 +0000
12:49:37.380 -> Sending hello
12:49:37.484 -> 250-mail.smtp2go.com Hello 192.168.10.96 [181.128.100.159]
12:49:37.484 -> 250-SIZE 52428800
12:49:37.484 -> 250-8BITMIME
12:49:37.484 -> 250-DSN
12:49:37.484 -> 250-PIPELINING
12:49:37.484 -> 250-AUTH CRAM-MD5 PLAIN LOGIN
12:49:37.484 -> 250-CHUNKING
12:49:37.484 -> 250-STARTTLS
12:49:37.484 -> 250-PRDR
12:49:37.484 -> 250 HELP
12:49:37.587 -> 334 VXNlcm5hbWU6
12:49:37.657 -> 334 UGFzc3dvcmQ6
12:49:37.759 -> 235 Authentication succeeded
12:49:37.862 -> 250 OK
12:49:38.271 -> 250 Accepted <jr@strele.ws>
12:49:38.374 -> 354 Enter message, ending with "." on a line by itself
12:49:38.407 -> Reset on Y/M/D/H/M/S,2020-6-25,12:42:14  -----------beginning of first file
12:49:38.407 -> Date, Time, EC(uS), pH, Temp(C), Filter(Bar), Bal(%)
12:49:38.441 -> 2020-6-25,12:45,10,3.91,25.6,2.76,217 ------------end of first file
12:49:38.474 -> Reset on Y/M/D/H/M/S,2020-6-25,12:42:14------begin second file
12:49:38.474 -> Date, Time, RainTank(m3), Line(bar), CircPump(bar)
12:49:38.474 -> 2020-6-25,12:45,24.42,3.17,0.38 -------------------end second file
12:49:38.612 -> 250 OK id=1joW0H-IbZpCc-Nr
12:49:38.716 -> 221 mail.smtp2go.com closing connection
12:49:38.785 -> disconnected
12:49:38.785 -> Email sent

BUT, the email only contains the text and the first file. The second one is nowhere to be found...

I'm probably parsing it together wrong

Cheers

trilife:
Thanks BLH64;

That helped, but there's still a bug.

  client.println("Subject: Pump Room Report");

//------- Body of EMAIL-----------
  client.write("MIME-Version: 1.0\r\n");
  client.write("Content-Type: Multipart/mixed; boundary=frontier\r\n\r\n");
  client.write("--frontier\r\n");
  client.write("Content-Type: text/plain\r\n\r\n");
  //-------text portion of email------------
  client.print("IP Address: "); client.println(Ethernet.localIP());
  client.print("Date/Time: "); emailClockDisplay();
  client.println("Pool");
  client.print("Pool EC    : "); client.print(ezoReading[eC], 0); client.println(" uS");
  client.print("Pool Temp  : "); client.print(ezoReading[rTD], 1); client.println(" C");
  client.print("Pool pH    : "); client.print(ezoReading[pH], 2); client.println(" pH");
  client.print("Pool Filter: "); client.print(pReading[poolFilter - 8]); client.println(" bar");
  client.print("BalanceTank: "); client.print(pReading[balanceTank - 8]); client.println(" %");

client.println("House");
  client.print("Rain Tank Level: "); client.print(pReading[rainTank - 8]); client.println(" m3");
  client.print("House Pressure : "); client.print(pReading[houseLine - 8]); client.println(" bar");
  client.print("Recirc Pressure: "); client.print(pReading[recircFilter - 8]); client.println(" bar");
  client.println();
  //-------eof text portion-----------

//---send file header---
  client.write("--frontier\r\n");
  client.write("Content-Type: text/plain\r\n");
  client.write("Content-Disposition: attachment; filename=poolLog.csv\r\n\r\n");

int clientCount = 0;  //send file
  poolFile = SD.open("poolLog.csv");
  int myint;
  if (poolFile) {
    while (poolFile.available()) {
      myint = poolFile.read();
      client.write(myint);
      Serial.write(myint);
    }
    client.print("\r\n");
    poolFile.close();
  }
  else Serial.println(F("File open failed"));
  //---send file footer---
  client.write("--frontier--\r\n");
 
//---send file header---
  client.write("--frontier\r\n");
  client.write("Content-Type: text/plain\r\n");
  client.write("Content-Disposition: attachment; filename=houseLog.csv\r\n\r\n");

clientCount = 0;  //send file
  houseFile = SD.open("houseLog.csv");
  //int myint;
  if (houseFile) {
    while (houseFile.available()) {
      myint = houseFile.read();
      client.write(myint);
      Serial.write(myint);
    }
    client.print("\r\n");
    houseFile.close();
  }
  else Serial.println(F("File open failed"));
  //---send file footer---
  client.write("--frontier--\r\n");
  client.println("."); //---eof email---
 
 
  if (!eRcv()) return 0;

//Serial.println(F("Sending QUIT"));
  client.println("QUIT");
  if (!eRcv()) return 0;

client.stop();

Serial.println(F("disconnected"));
  needToSendEmail = false;    //sent email successfully, no need to send again, until flag is set.
  return 1;
}





The Serial monitor goes through both files, I do get an "email sent" message:



Email connected
12:49:37.380 -> 220 mail.smtp2go.com ESMTP Exim 4.92-S2G Thu, 25 Jun 2020 17:49:36 +0000
12:49:37.380 -> Sending hello
12:49:37.484 -> 250-mail.smtp2go.com Hello 192.168.10.96 [181.128.100.159]
12:49:37.484 -> 250-SIZE 52428800
12:49:37.484 -> 250-8BITMIME
12:49:37.484 -> 250-DSN
12:49:37.484 -> 250-PIPELINING
12:49:37.484 -> 250-AUTH CRAM-MD5 PLAIN LOGIN
12:49:37.484 -> 250-CHUNKING
12:49:37.484 -> 250-STARTTLS
12:49:37.484 -> 250-PRDR
12:49:37.484 -> 250 HELP
12:49:37.587 -> 334 VXNlcm5hbWU6
12:49:37.657 -> 334 UGFzc3dvcmQ6
12:49:37.759 -> 235 Authentication succeeded
12:49:37.862 -> 250 OK
12:49:38.271 -> 250 Accepted jr@strele.ws
12:49:38.374 -> 354 Enter message, ending with "." on a line by itself
12:49:38.407 -> Reset on Y/M/D/H/M/S,2020-6-25,12:42:14  -----------beginning of first file
12:49:38.407 -> Date, Time, EC(uS), pH, Temp(C), Filter(Bar), Bal(%)
12:49:38.441 -> 2020-6-25,12:45,10,3.91,25.6,2.76,217 ------------end of first file
12:49:38.474 -> Reset on Y/M/D/H/M/S,2020-6-25,12:42:14------begin second file
12:49:38.474 -> Date, Time, RainTank(m3), Line(bar), CircPump(bar)
12:49:38.474 -> 2020-6-25,12:45,24.42,3.17,0.38 -------------------end second file
12:49:38.612 -> 250 OK id=1joW0H-IbZpCc-Nr
12:49:38.716 -> 221 mail.smtp2go.com closing connection
12:49:38.785 -> disconnected
12:49:38.785 -> Email sent





BUT, the email only contains the text and the first file. The second one is nowhere to be found...

I'm probably parsing it together wrong

Cheers

OK, three days no answers. Must be a tough one...

I contacted SMTP2Go as well. No information there either. There's a post in the forum, stating "thanks we solved the problem", but they didn't post the solution. At this point, I have two solutions: fuse the two attachments into one, or send two emails... either one feels like I'm giving up

Ok,

I didn't give up. But it took a couple of hours to make it work. Still don't understand the whole HTTP comms protocol, but as the code stands now, it emails some text in the body of the mail AND sends two x.csv attachments...

client.println("Subject: Pump Room Report");

  //------- Body of EMAIL-----------
  client.write("MIME-Version: 1.0\r\n");
  client.write("Content-Type: Multipart/mixed; boundary=frontier\r\n\r\n"); // set up multipart email

  client.write("--frontier\r\n"); // with --frontier the body of the text starts
  client.write("Content-Type: text/plain\r\n"); // plain text for the body of the email
  
  client.println("Body of text for the email here");

  //-------eof text portion-----------

  int myint;
  //---send file header for Pool---
  client.write("--frontier\r\n"); //need this --frontier to let the server know a new section is starting
  client.write("Content-Type: text/csv\r\n"); // what type is it. In this case text with csv
  client.write("Content-Disposition: attachment; filename=poolLog.csv\r\n"); // it goes into an attachment
  
  poolFile = SD.open("poolLog.csv");    // send poolLog data
  if (poolFile) {                   
    while (poolFile.available()) {
      myint = poolFile.read();
      client.write(myint);
      Serial.write(myint);
    }
    client.print("\r\n");
    poolFile.close();
  } else Serial.println(F("File open failed"));

  //---send file header for House---
  client.write("--frontier\r\n"); // if you don't include this --frontier, the context of the next file ends up in the first file!!!
  client.write("Content-Type: text/csv\r\n");
  client.write("Content-Disposition: attachment; filename=houseLog.csv\r\n");
  
  houseFile = SD.open("houseLog.csv");    // send houseLog data
  if (houseFile) {                  
    while (houseFile.available()) {
      myint = houseFile.read();
      client.write(myint);
      Serial.write(myint);
    }
    client.print("\r\n");
    houseFile.close();
  } else Serial.println(F("File open failed"));

  //---send file footer---
  client.write("--frontier\r\n"); // close the section.
  client.println("."); //---eof email---

  if (!eRcv()) return 0;

  //Serial.println(F("Sending QUIT"));
  client.println("QUIT");
  if (!eRcv()) return 0;

  client.stop();

  Serial.println(F("disconnected"));
  needToSendEmail = false;    //sent email successfully, no need to send again, until flag is set.
  return 1;
}

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

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

  respCode = client.peek();
  while (client.available()) {
    thisByte = client.read();
    Serial.write(thisByte);
  }

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

  return 1;
}

void efail() {
  byte thisByte = 0;
  int loopCount = 0;
  client.println(F("QUIT"));
  while (!client.available()) {
    delay(1);
    loopCount++;
    if (loopCount > 10000) {  // if nothing received for 10 seconds, timeout
      client.stop();
      Serial.println(F("\r\nTimeout"));
      return;
    }
  }
  while (client.available()) {
    thisByte = client.read();
    Serial.write(thisByte);
  }
  client.stop();
  Serial.println(F("disconnected"));
}

If anyone has a good reference on how to deal with these http commands in Arduino, please feel free to share.

Lastly, SMTP2GO is a pain... Has Arduino figured out how to send emails via GMAIL yet? It would be sooooo much easier....

Cheers