ending image attachment via smtp2go only sends blank file

Hi everyone,

I am using a Redboard with an Ethernet Shield 2. I have an SD card with an image file called “motion.jpg” inserted in the shield, and I am attempting to send this file as an attachment via an email relayed through smtp2go. I can get the email to send well enough, and it even has an attached file called “motion.jpg”. This file, however, has 0 bytes. I’ve done some searching through the Arduino boards, and have come across other posts with code that should encode the image file to send as an attachment. I think I am following along well enough, but I am missing something. Since I am fairly new to this, what I am missing is probably obvious. Can someone please tell me where I am going wrong?

Here is the code that I am using:

/*
   Email client sketch for IDE v1.0.5 and w5100/w5200
   Posted 7 May 2015 by SurferTim
   Encoding Routines by Razorblade
   https://www.base64encode.org/ Encoder Site
   http://forum.arduino.cc/index.php?topic=296897.0 SurferTim's Addition Thread
   http://forum.arduino.cc/index.php?topic=67701.30 Encoding Thread by Razorblade

*/
#include <SD.h>
#include <SPI.h>
#include <Ethernet2.h> 

#define W5200_CS  10 //Denotes Pin 10 as W5200 Pin
#define SDCARD_CS 4  //Denotes Pin 4 as SD Card Pin

File SendFile;
 
static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

//Mac must be unique
byte mac[] = { 0, 0, 0, 0, 0, 0 };

char server[] = "mail.smtp2go.com";
int port = 80;
EthernetClient client;

void setup()
{
  Serial.begin(9600);
  //Initialize SD Card
  Serial.print("Initializing SD card...");
  pinMode(W5200_CS, OUTPUT);
  digitalWrite(W5200_CS,HIGH);
  pinMode(SDCARD_CS,OUTPUT);
  if (!SD.begin(SDCARD_CS)) {
    Serial.println("Initialization Failed!");
    return;
  }
  Serial.println("Initialization Successful");
  delay(2000);
  
  //Ethernet.begin(mac, ip, gateway, gateway, subnet);
  
  Serial.println("Trying to connect");
  if (!Ethernet.begin(mac)){
    Serial.println("Failed to DHCP");
    // verifyng connection
    while(true);
  }
  delay(10000);
  // IP address is:
  Serial.print("IP address: ");
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    Serial.print(".");
  }
  Serial.println();

 

  Serial.println(F("Ready. Press 'e' to send."));
}

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");
  if(!eRcv()) return 0;

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

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

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

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

//change to recipient address**************************
  Serial.println(F("Sending To"));
  client.println("RCPT To: <receiver@gmail.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: You <receiver@gmail.com>");

//change to your address**************************
  client.println("From: Me <sender@gmail.com>");
  client.println("Subject: Arduino email test");
  
//****************************************************
//Start of Attach File
  SendFile =SD.open("motion.jpg",FILE_READ);
  client.print("Content-Type: image/jpg; name=\"motion.jpg\"\r\n");
  client.write("Content-Disposition: attachment; filename=motion.jpg\r\n");
  client.print("Content-Transfer-Encoding: base64\r\n\r\n");
  encode();
  SendFile.close();
//End of Attach File
//****************************************************
  client.print("\r\n.\r\nQUIT\n");
  if(!eRcv()) return 0;
  client.stop();
  //SendFile.close();
  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("isconnected"));
}

void encodeblock(unsigned char in[3],unsigned char out[4],int len) {
  out[0]=cb64[in[0]>>2]; out[1]=cb64[((in[0]&0x03)<<4)|((in[1]&0xF0)>>4)];
  out[2]=(unsigned char) (len>1 ? cb64[((in[1]&0x0F)<<2)|((in[2]&0xC0)>>6)] : '=');
  out[3]=(unsigned char) (len>2 ? cb64[in[2]&0x3F] : '=');
}

void encode() {
  unsigned char in[3],out[4];
  int i,len,blocksout=0;
  while (SendFile.available()!=0) {
    len=0;
    for (i=0;i<3;i++){
      in[i]=(unsigned char) SendFile.read();
      if (SendFile.available()!=0) len++;
      else in[i]=0;
    }
    if (len){
      encodeblock(in,out,len);
      for(i=0;i<4;i++) client.write(out[i]);
        blocksout++;
    }
    if (blocksout>=19||SendFile.available()==0){
      if (blocksout) client.print("\r\n");  blocksout=0;
    }
  }
}

This is what I see in the serial monitor when I run the code:

Initializing SD card...Initialization Successful
Trying to connect
IP address: 1.2.3.4.
Ready. Press 'e' to send.
Connected
220 mail.smtp2go.com ESMTP Exim 4.87 Thu, 18 Aug 2016 21:57:22 +0000
Sending Hello
250-mail.smtp2go.com Hello  [76.100.163.175]
250-SIZE 52428800
250-8BITMIME
250-DSN
250-PIPELINING
250-AUTH CRAM-MD5 PLAIN LOGIN
250-STARTTLS
250-PRDR
250 HELP
Sending authorizes login
334 VXNlcm5hbWU6
Sending User
334 UGFzc3dvcmQ6
Sending Password
235 Authentication succeeded
Sending From
250 OK
Sending To
250 Accepted <recipient@gmail.com>
Sending DATA
354 Enter message, ending with "." on a line by itself
Sending email
250 OK id=1baVJT-NRKK26-53
221 mail.smtp2go.com closing connection
disconnected
Email Sent

The card is initializing, but is it not being read?

Thanks in advance!

So it looks like my file is not opening. I placed a text file called “test.txt” on the SD card. It contained a single line of text to say “this is a test”. Running the example “ReadWrite” sketch from the IDE (with the “write” section commented out), I was able to successfully print out “this is a test”. I copied that code to my sketch (right after opening the file to start the attachment process) , and get "error opening “test.txt” ". I moved the block of code up a bit, between the card initialization and the starting of the Ethernet client, like so:

void setup()
{
  Serial.begin(9600);
  //Initialize SD Card
  Serial.print("Initializing SD card...");
  pinMode(W5200_CS, OUTPUT);
  digitalWrite(W5200_CS,HIGH);
  pinMode(SDCARD_CS,OUTPUT);
  if (!SD.begin(SDCARD_CS)) {
    Serial.println("Initialization Failed!");
    return;
  }
  Serial.println("Initialization Successful");
  delay(2000);
  
  //*******************************************************  
    File myFile = SD.open("test.txt");
  if (myFile) {
    Serial.println("test.txt:");

    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      Serial.write(myFile.read());
    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
  //*******************************************************
  
  //Ethernet.begin(mac, ip, gateway, gateway, subnet);
  
  Serial.println("Trying to connect");
  if (!Ethernet.begin(mac)){
    Serial.println("Failed to DHCP");
    // verifyng connection
    while(true);
  }
  delay(10000);
  // IP address is:
  Serial.print("IP address: ");
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    Serial.print(".");
  }
  Serial.println();


  Serial.println(F("Ready. Press 'e' to send."));
}

When I ran this code, I saw the following in the serial monitor:

Initializing SD card...Initialization Successful
test.txt:
This is atest to see if this file will send as an attachment in an email.Trying to connect
IP address: 192.168.1.23.
Ready. Press 'e' to send.
Connected
220 mail.smtp2go.com ESMTP Exim 4.87 Sat, 20 Aug 2016 18:18:32 +0000
Sending Hello
250-mail.smtp2go.com Hello  [76.100.163.175]
250-SIZE 52428800
250-8BITMIME
250-DSN
250-PIPELINING
250-AUTH CRAM-MD5 PLAIN LOGIN
250-STARTTLS
250-PRDR
250 HELP
Sending authorizes login
334 VXNlcm5hbWU6
Sending User
334 UGFzc3dvcmQ6
Sending Password
235 Authentication succeeded
Sending From
250 OK
Sending To
250 Accepted <comp444.donfrankrice@gmail.com>
Sending DATA
354 Enter message, ending with "." on a line by itself
Sending email
250 OK id=1bbAqo-NRKGwi-0F
221 mail.smtp2go.com closing connection
disconnected
Email Sent

Do I need to disable the Ethernet pin (10) before opening and encoding my file? I have a different sketch that pulls an image from an IP camera and saves it to the SD card, but I do not have to do anything special to make that happen. Is it significant that I can read the contents of the text file from setup(), but not inside loop()?

I got it! I took SendFile =SD.open(“motion.jpg”,FILE_READ); and moved it up to setup(), just after the card initialization. Everything worked well after that!