Help on understand when to use "\r" , "\n" , "\r\n" , '\r' , '\n' , '\r\n'

I an using a NodeMCU 0.9 (ESP-12 Module) to measure three DS18B20. The script reads the sensors every second or two for 1-2 min. then averages the reading and put the averages in a string that is sent out in a email ~hour or so. The script then it does a ESP.restart to start over. This was the only way I could get the script to send an email more than once.

I would take the emails, copy the text strings, copy and paste them into excel for processing. The text string would go into excel as one string and I had to parse and put into 4 columns. Three temperature columns and one time column.

I tried include various combinations of \r and \n so that each line of data would be copy into excel as a separate row so I could delimit them using commas and a tab.

To test out what I needed I used a send one email script and change the \r & \n combinations. I figured out what I needed do but I can't understand what rules they follow.

Can someone explain why I can't add "\r" , "/n" , "\r\n" to a string in a Serial.print to get a CR. But I can if they are added as string variable?

Second part of the question: It seems that "/n" , "\r\n" can be added to a string (as a string variable) if using Serial.print but not "\r"? But if in the string I am sending out in an email I have to use "\r", "\r\n" because "/n" will not work?

I have included full email once script I am using and the results from everything that worked and did not work. I have to believe I am not the only one to have run into this using "\r" , "/n" , "\r\n". Sorry for the long drawn out story but you can't search for anything with a " or ' using Google. It just ignores the " and ' characters in the search.


//THESE ARE THE RESULTS OF VARIOUS CHANGES IN THE CODE LINES OF INTEREST

CR1="\r\n";   
Temp1 = "This appears on one line" + CR1 + "And this appears on a new line";


CR1="\r\n And this appears on a new line";   
Temp1 = "This appears on one line" +  CR1;


//////////////////////////////////////////////////////////////////////////////
Temp1 = "This appears on one line" +  "\r\n And this appears on a new line";

/*
G:\Arduino\Email_Single_Send_Latest\Email_Single_Send_Latest.ino: In function 'void setup()':
G:\Arduino\Email_Single_Send_Latest\Email_Single_Send_Latest.ino:133:36: error: invalid operands of types 'const char [25]' and 'const char [34]' to binary 'operator+'
  133 |     else
      |                                    ^                                       
      |         |                             |
      |         const char [25]               const char [34]
Multiple libraries were found for "SD.h"
  Used: C:\Users\Tom5810\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\libraries\SD
  Not used: C:\Users\Tom5810\AppData\Local\Arduino15\libraries\SD
exit status 1

Compilation error: invalid operands of types 'const char [25]' and 'const char [34]' to binary 'operator+'
*/
////////////////////////////////////////////////////////////////////////////
   
Temp1 = "This appears on one line" +  "\r\n" + "And this appears on a new line";

 /*
G:\Arduino\Email_Single_Send_Latest\Email_Single_Send_Latest.ino: In function 'void setup()':
G:\Arduino\Email_Single_Send_Latest\Email_Single_Send_Latest.ino:133:36: error: invalid operands of types 'const char [25]' and 'const char [3]' to binary 'operator+'
  133 |     else
      |                                    ^        
      |         |                             |
      |         const char [25]               const char [3]
Multiple libraries were found for "SD.h"
  Used: C:\Users\Tom5810\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\libraries\SD
  Not used: C:\Users\Tom5810\AppData\Local\Arduino15\libraries\SD
exit status 1

Compilation error: invalid operands of types 'const char [25]' and 'const char [3]' to binary 'operator+'
*/
////////////////////////////////////////////////////////////////////////////

CR1="\r\n";   
Temp1 = "This appears on one line" + CR1 + "And this appears on a new line"; 
Serial.println("test>>>>>>>>>>>>>>>>      " + Temp1);
      delay(100);
 Serial.println(Temp1);
      delay(100);
/*
SERIAL PRINTS THIS:
test>>>>>>>>>>>>>>>>      This appears on one line
And this appears on a new line
This appears on one line
And this appears on a new line
*/
////////////////////////////////////////////////////////////////////////////


CR1="\n";   
Temp1 = "This appears on one line" + CR1 + "And this appears on a new line"; 
Serial.println("test>>>>>>>>>>>>>>>>      " + Temp1);
      delay(100);
 Serial.println(Temp1);
      delay(100);
/*
SERIAL PRINTS THIS:
test>>>>>>>>>>>>>>>>      This appears on one line
And this appears on a new line
This appears on one line
And this appears on a new line
*/
////////////////////////////////////////////////////////////////////////////

CR1="\r";   
Temp1 = "This appears on one line" + CR1 + "And this appears on a new line"; 
Serial.println("test>>>>>>>>>>>>>>>>      " + Temp1);
      delay(100);
 Serial.println(Temp1);
      delay(100);
/*
SERIAL PRINTS THIS:
test>>>>>>>>>>>>>>>>      This appears on one lineAnd this appears on a new line
This appears on one lineAnd this appears on a new line


HOWEVER IF I COPY (CTRL-C / CTRL-V) THE ABOVE TEXT FROM THE ARDUINO SERIAL MONITOR IT PUTS THIS NOTEPAD DOC A CR IS INSERTED AS SHOWN BELOW:
test>>>>>>>>>>>>>>>>      This appears on one line
And this appears on a new line
This appears on one line
And this appears on a new line

*/
////////////////////////////////////////////////////////////////////////////
//WITH THIS CODE:

CR1="\n";   
Temp1 = "This appears on one line" +  CR1 + "And this appears on a new line";  
   
  //Send raw text message
  String textMsg = "Hello World! - Sent from ESP board " +  Temp1;

//THE RECEIVED EMAIL LOOKS LIKE THIS:
//Hello World! - Sent from ESP board This appears on one line And this appears on a new line

////////////////////////////////////////////////////////////////////////////

//WITH THIS CODE:

CR1="\r";   // or if I use CR1="\r\n";  
Temp1 = "This appears on one line" +  CR1 + "And this appears on a new line";  
   
  //Send raw text message
  String textMsg = "Hello World! - Sent from ESP board " +  Temp1;

//THE RECEIVED EMAIL LOOKS LIKE THIS:
//Hello World! - Sent from ESP board This appears on one line
//And this appears on a new line

////////////////////////////////////////////////////////////////////////////

THIS IS THE FULL SCRIPT >>>>>>>>>>>>>>>>>>>>>>>>

/*

SENDS ONE SINGLE EMAIL MODIFIED EXAMPLE BY ME
  Rui Santos
  Complete project details at:
   - ESP32: https://RandomNerdTutorials.com/esp32-send-email-smtp-server-arduino-ide/
   - ESP8266: https://RandomNerdTutorials.com/esp8266-nodemcu-send-email-smtp-server-arduino/


   https://raw.githubusercontent.com/RuiSantosdotme/Random-Nerd-Tutorials/master/Projects/ESP/ESP_Email_Simple.ino
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  Example adapted from: https://github.com/mobizt/ESP-Mail-Client
*/

#include <Arduino.h>
#if defined(ESP32)
  #include <WiFi.h>
#elif defined(ESP8266)
  #include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>

#define WIFI_SSID "XXXXXXXXX"
#define WIFI_PASSWORD "XXXXXXXXXX"

/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */
#define SMTP_HOST "server146.web-hosting.com"
#define SMTP_PORT 465


#define AUTHOR_PASSWORD "XXXXXXXXXXXXXXXXXXXXX"

/* Recipient's email*/
#define RECIPIENT_EMAIL "XXX@XXXXXXXXXX.com"

/* Declare the global used SMTPSession object for SMTP transport */
SMTPSession smtp;

/* Callback function to get the Email sending status */

 String CR1 = "";
 String Temp1 = "";


void smtpCallback(SMTP_Status status);

void setup(){

CR1="\r" ;
Temp1 = "This appears on one line" + CR1 +  "And this appears on a new line";

  Serial.begin(115200);
 delay(100);
Serial.println();
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
      delay(100);
  Serial.print("Connecting to Wi-Fi");
        delay(100);
  while (WiFi.status() != WL_CONNECTED){
    Serial.print(".>");
    delay(300);
  }
  Serial.println();
        delay(100);
  Serial.print("Connected with IP: ");
        delay(100);
  Serial.println(WiFi.localIP());
        delay(100);
  Serial.println("test>>>>>>>>>>>>>>>>      " + Temp1);
      delay(100);
 Serial.println(Temp1);
      delay(100);


  /*  Set the network reconnection option */
  MailClient.networkReconnect(true);

  /** Enable the debug via Serial port
   * 0 for no debugging
   * 1 for basic level debugging
   *
   * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
   */
  smtp.debug(1);

  /* Set the callback function to get the sending results */
  smtp.callback(smtpCallback);

  /* Declare the Session_Config for user defined session credentials */
  Session_Config config;

  /* Set the session config */
  config.server.host_name = SMTP_HOST;
  config.server.port = SMTP_PORT;
  config.login.email = AUTHOR_EMAIL;
  config.login.password = AUTHOR_PASSWORD;
  config.login.user_domain = "";

  /*
  Set the NTP config time
  For times east of the Prime Meridian use 0-12
  For times west of the Prime Meridian add 12 to the offset.
  Ex. American/Denver GMT would be -6. 6 + 12 = 18
  See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets
  */
  config.time.ntp_server = F("pool.ntp.org,time.nist.gov");
  config.time.gmt_offset = 3;
  config.time.day_light_offset = 0;

  /* Declare the message class */
  SMTP_Message message;

  /* Set the message headers */
  message.sender.name = F("ESP");
  message.sender.email = AUTHOR_EMAIL;
  message.subject = F("ESP Test Email ");
  message.addRecipient(F("Tom"), RECIPIENT_EMAIL);
    
  /*Send HTML message*/
  /*String htmlMsg = "<div style=\"color:#2f4468;\"><h1>Hello World!</h1><p>- Sent from ESP board</p></div>";
  message.html.content = htmlMsg.c_str();
  message.html.content = htmlMsg.c_str();
  message.text.charSet = "us-ascii";
  message.html.transfer_encoding = Content_Transfer_Encoding::enc_7bit;*/

CR1="\n";   
Temp1 = "This appears on one line" +  CR1 + "And this appears on a new line";  
   
  //Send raw text message
  String textMsg = "Hello World! - Sent from ESP board " +  Temp1;
  message.text.content = textMsg.c_str();
  message.text.charSet = "us-ascii";
  message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit;
  
  message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low;
  message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay;


  /* Connect to the server */
  if (!smtp.connect(&config)){
    ESP_MAIL_PRINTF("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str());
    return;
  }

  if (!smtp.isLoggedIn()){
    Serial.println("\nNot yet logged in.");
  }
  else{
    if (smtp.isAuthenticated())
      Serial.println("\nSuccessfully logged in.");
    else
      Serial.println("\nConnected with no Auth.");
  }

  /* Start sending Email and close the session */
  if (!MailClient.sendMail(&smtp, &message))
    ESP_MAIL_PRINTF("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str());

}

void loop(){
}




/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status){
  /* Print the current status */
  Serial.println(status.info());

  /* Print the sending result */
  if (status.success()){
    // ESP_MAIL_PRINTF used in the examples is for format printing via debug Serial port
    // that works for all supported Arduino platform SDKs e.g. AVR, SAMD, ESP32 and ESP8266.
    // In ESP8266 and ESP32, you can use Serial.printf directly.

    Serial.println("----------------");
    ESP_MAIL_PRINTF("Message sent success: %d\n", status.completedCount());
    ESP_MAIL_PRINTF("Message sent failed: %d\n", status.failedCount());
    Serial.println("----------------\n");

    for (size_t i = 0; i < smtp.sendingResult.size(); i++)
    {
      /* Get the result item */
      SMTP_Result result = smtp.sendingResult.getItem(i);

      // In case, ESP32, ESP8266 and SAMD device, the timestamp get from result.timestamp should be valid if
      // your device time was synched with NTP server.
      // Other devices may show invalid timestamp as the device time was not set i.e. it will show Jan 1, 1970.
      // You can call smtp.setSystemTime(xxx) to set device time manually. Where xxx is timestamp (seconds since Jan 1, 1970)
      
      ESP_MAIL_PRINTF("Message No: %d\n", i + 1);
      ESP_MAIL_PRINTF("Status: %s\n", result.completed ? "success" : "failed");
      ESP_MAIL_PRINTF("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str());
      ESP_MAIL_PRINTF("Recipient: %s\n", result.recipients.c_str());
      ESP_MAIL_PRINTF("Subject: %s\n", result.subject.c_str());
    }
    Serial.println("----------------\n");

    // You need to clear sending result as the memory usage will grow up.
    smtp.sendingResult.clear();
  }
}

'\r' and '\n' are character constants exactly the same as 'a', 'b' and 'c'. The backslash is an escape character taken as a signal that what follows should be interpreted differently to what it would have meant in the absence of the backslash.

You may have seen it used to allow having a quotation mark in a quoted string.

I have no idea where you have ever seen a slash used as you have done in your title.

So where did you, what have I been forgetting or overlooking or yet to learn?

a7

The backslash escape character translates a \n into a NL and \r into a CR control character.
A /n instead will display as just those two characters.

Perhaps part of the problem is in the tools that are receiving the characters. I'm sure that the Arduino is sending out the "\n\r" characters but the Arduino Serial Monitor itself isn't acting on the "\r".

The email goes through SMTP and the protocols and intevening programs can change line endings so they work on your end device.

Maybe try a better terminal program that can handle line endings better?

My mistake the "/" were in error they should have all been "". Will try to correct.

I think you are correct regarding the terminal. It is odd that for a Arduino IDE using a \n with Serial.print works as a NL but not for the email text. For the email text the \r works as a NL but not the \n.

Just incase anyone else is trying to understand what I ran across. I just ran across this Form post. It helped me to understand what maybe going on. It also helped me to understand NL and CR.

Escaped characters are handled in the parser before compilation.

Right. New line rolls the platten up one line, carriage return moves it back to its left-most position.

When there are such mechanical things.

Line endings are a tue PITA, between Unix, MS-DOS and MacOS, so you kinda have to roll with that as circumstances demand.

a7

1 Like

there are 2 approaches for terminating a line, starting a new line as well as starting the line at the beginning of the line:

  • dos applications use \r\n
  • unix uses \n

unix has standard commands for converting files between the two formats: dos2unix and unix2dos

Mac uses \n\r

that's odd, the reason the carrage return is first is to allow more time for the carrage to move fully to the left on a mechanical tty

1 Like

Ancient Mac was \r, my much newer Mac follows UNIX/BSD with \n. Old terminals didn't care which order as long as you had both of them.

1 Like

Haha, you mean they all should have been "\".

I'll let you figure out how I did that.

a7

Yes"" , I was able to make the correction.

I did not try and see if the order made a difference. As someone pointed out in another post I saw," on a typewriter the reason for a separate CR and NL was to allow one to type over a line by just doing a CR. Mechanical typewriter are a thing of the past and you can't type over text using a CR. The NL comes with a CR or they have become the same thing in the digital word.

I think a decent terminal emulator will do carriage return and happily overwrite what was on the line to begin with.

I can't test the several I use just now, but I would be surprised if they did not, or could not be configured to do.

a7

With the Arduino IDE Serial Monitor a \n or \r\n gives you a NL and \r does nothing. A \n in a string sent by email using an Arduino does not show up on the emailed text but a \r or \r\n gives you a new line. No idea why but this is what I seen. Drove me nuts.

they are 2 separate ASCII characters

You may be correct. Just have to know the rules and adjust.