Sending image attachment via smtp2go only sends blank file

I am having similar problems to what Ditchpanther was having at the beginning of this thread. I have an image file called “motion.jpg” on an SD card that sits on my Arduino Ethernet Shield 2.

I can get the email to send, and it even has an attachment called “motion.jpg”, but it has 0 bytes. Ditchpanther indicated that he could get it to work to send pictures, and I think I have used his code correctly (I have been over several different forum posts, and may have jumbled things together). I am hoping that someone can 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;
    }
  }
}

And here is what I see in the Serial monitor:

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

As I look through this again before posting, I wonder if the issue is with my shield. Looking at the information from Sparkfun, my shield has a W5500 chip. The code I used seems to be written for a W5100/W5200 chip. Is that my problem, or do I have something else going on? I’m pretty new to all of this, so I hope you will bear with me.

Thanks for any help you can provide!

This worked for me. I use the Wiznet library. It should work with the w5100, w5200, and w5500(default).

/*
   Email client sketch for IDE v1.6.9 and w5100/w5200/w5500
   Posted 18 August 2016 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 );

// change server to your email server ip or domain
// IPAddress server( 1, 2, 3, 4 );
char server[] = "smtpcorp.com";
int port = 2525;

EthernetClient client;

char b64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char tBuf[64];
char b64Buf[128];
byte bufCount;
File myFile;

void setup()
{
  Serial.begin(115200);
  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);

//  Ethernet.begin(mac, ip, gateway, gateway, subnet); 
  while(!Ethernet.begin(mac)) {
    Serial.println(F("DHCP failed."));
    delay(2000);
  }

  delay(2000);

  if(!SD.begin(4)) Serial.println(F("SD failed"));
  
  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;
//  char tBuf[64];
  
  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"));
  strcpy_P(tBuf,PSTR("EHLO\r\n"));  
  client.write(tBuf);
  if(!eRcv()) return 0;

  Serial.println(F("Sending auth login"));
  strcpy_P(tBuf,PSTR("auth login\r\n"));  
  client.write(tBuf);
  if(!eRcv()) return 0;

  Serial.println(F("Sending User"));
  strcpy_P(tBuf,PSTR("userb64\r\n"));  
  client.write(tBuf);
  if(!eRcv()) return 0;

  Serial.println(F("Sending Password"));
  strcpy_P(tBuf,PSTR("paswordb64r\n"));  
  client.write(tBuf);
  if(!eRcv()) return 0;

// change to your email address (sender)
  Serial.println(F("Sending From"));
  strcpy_P(tBuf,PSTR("MAIL From: <me@mydomain.com>\r\n"));  
  client.write(tBuf);
  if(!eRcv()) return 0;

// change to recipient address
  Serial.println(F("Sending To"));
  strcpy_P(tBuf,PSTR("RCPT To: <you@yourdomain.com>\r\n"));  
  client.write(tBuf);
  if(!eRcv()) return 0;

  Serial.println(F("Sending DATA"));
  strcpy_P(tBuf,PSTR("DATA\r\n"));  
  client.write(tBuf);
  if(!eRcv()) return 0;

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

// change to recipient address
  strcpy_P(tBuf,PSTR("To: Your Name <you@yourdomain.com>\r\n"));  
  client.write(tBuf);

// change to your address
  strcpy_P(tBuf,PSTR("From: My Name <me@mydomain.com>\r\n"));  
  client.write(tBuf);

  client.println("Subject: Arduino email image");

  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 an inage from my Arduino!\r\n");
  
  client.write("--frontier\r\n");
  client.write("Content-Type: image/jpeg\r\n");
  client.write("Content-Disposition: attachment; filename=testjpg.jpg\r\n");
  client.print("Content-Transfer-Encoding: base64\r\n\r\n");

// this is where you would send your file
  int clientCount = 0;

// change this to a valid jpg image file name
  myFile = SD.open("motion.jpg");
  
  if(myFile) {
    encode();
    myFile.close();                  
  }
  else {
    Serial.println(F("File open failed"));
  }

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

  client.println(".");
  if(!eRcv()) return 0;

  Serial.println(F("Sending QUIT"));
  strcpy_P(tBuf,PSTR("QUIT\r\n"));  
  client.write(tBuf);
  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("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"));
}

void encode() {
  unsigned char in[3],out[4];
  int i,len,blocksout=0;
  while (myFile.available()!=0) {
    len=0;
    for (i=0;i<3;i++){
      in[i]=(unsigned char) myFile.read();
      if (myFile.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||myFile.available()==0){
      if (blocksout) client.print("\r\n");  blocksout=0;
    }
  }
}

void encodeblock( byte *in, byte *out, int len )
{
    out[0] = (byte) b64Chars[ (in[0] >> 2) ];
    out[1] = (byte) b64Chars[ (in[0] & 0x03) << 4 | (in[1] & 0xf0) >> 4 ];
    out[2] = (byte) (len > 1 ? b64Chars[ (in[1] & 0x0f) << 2 | (in[2] & 0xc0) >> 6 ] : '=');
    out[3] = (byte) (len > 2 ? b64Chars[ (in[2] & 0x3f) ] : '=');
}

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!

If you move the file open call to setup, you can only send the image once.