• a curl version not too old (on old versions curl didn’t manage the sending of emails)
  • an existing SMTP server

Basic example without encoding headers

Case of an existing SMTP server without authentication ( can be replaced by the domain name of your smtp server or its IP address):

curl smtp:/ --mail-from '' --mail-rcpt 'therecipient@recipientdomain' -T <(echo -e 'From:\nTo: therecipient@recipientdomain\nSubject: TEST send mail with curl\n\nThis is a test)

At the end you can see “\nSubject: TEST send mail with curl\n\nThis is a test” –> here Subject introduce the subject fied of the mail, and the two \n\n introduce the content of the mail (the body) which is here “This is a test”.

In case of an existing SMTP server with authentication (adding of -u ‘user:password’):

curl smtp:/ --mail-from '' --mail-rcpt 'therecipient@recipientdomain' -u 'user:password' -T <(echo -e 'From:\nTo: therecipient@recipientdomain\nSubject: TEST send mail with curl\n\nThis is a test)

Example with UTF8 encoding header: send to multiple recipient + escape double quotein your content

For instance without UTF8 encoding header, the following sent text “ERREUR trouvée un autre process est en cours d’exécution.” whould be received as “ERREUR trouvé un autre process est en cours d’exécution.”

There is also another encoding header called Content-Transfer-encoding, but this header is already set by default to the value ‘7bit’, and only exists for compatibility with old smtp servers. You probably won’t have to deal with but if you want to have a look the rfc is here.

Then we juste have to insert the header ‘Content-type: text/plain;charset=utf-8’.

To easily reuse the previous syntax, you can create a small script for example the previous code will then looks like (with the encoding header):

# This script send an email to an existing smtp server
# Read of parameter

# We remove simple quotes inside MAIL_TO value:
CLEAN_MAIL_TO=$(echo $MAIL_TO | sed "s/'//g")
# We escape double quotes inside CONTENT value. I mean we replace double quotes " by \"
ESCAPED_CONTENT=$(echo "$CONTENT" | sed 's/"/\"/g')
for email in $CLEAN_MAIL_TO
  curl smtp://${HOST} --mail-from "$MAIL_FROM" --mail-rcpt "$email" -T <(echo -e "From: ${MAIL_FROM}\nTo: ${email}\nContent-type: text/plain;charset=utf-8\nSubject: ${SUBJECT}\n\n${ESCAPED_CONTENT}")
./ '' 'therecipient@recipientdomain rcpt2@rcptdomain rcpt3@rcptdomain' "TEST send mail with curl" "This is a test"
  • It’s important to notice that when you want to pass recipients in a string containing spaces you have to add simple quote around $MAIL_TO, and then englobing douple quotes in order the variable is interpreted from the call:
MAIL_TO='therecipient@recipientdomain rcpt2@rcptdomain rcpt3@rcptdomain'
./ '' "'$MAIL_TO'" "TEST send mail with curl" "This is a test"

In this example, the simple quotes prevent $MAIL_TO to be interpreted as three distinct parameters (therecipient@recipientdomain rcpt2@rcptdomain rcpt3@rcptdomain), thus inside we remove these simple quotes.

Also, it’s very important to escape the double quote in your content, because if your content has double quotes in it, it will be interpreted as the end of the <(echo -e “From… string, and we don’t want this. Then we have escaped double quotes like this:

ESCAPED_CONTENT=$(echo "$CONTENT" | sed 's/"/\"/g')

To understand how curl works for sending emails

If you want to understand you can have a look to the curl man page, here an extract:

$> man curl
   -T, --upload-file <file>
          	This  transfers  the specified local file to the remote URL. If there is no file part in the specified URL, curl will append the local file name. NOTE that you must use a
          	trailing / on the last directory to really prove to Curl that there is no file name or curl will think that your last directory name is the remote file name to use.  That
          	will most likely cause the upload operation to fail. If this is used on an HTTP(S) server, the PUT command will be used.

          	Use the file name "-" (a single dash) to use stdin instead of a given file.  Alternately, the file name "." (a single period) may be specified instead of "-" to use stdin
          	in non-blocking mode to allow reading server output while stdin is being uploaded.

          	You can specify one -T, --upload-file for each URL on the command line. Each -T, --upload-file + URL pair specifies what to upload and to where. curl also supports "glob‐
          	bing" of the -T, --upload-file argument, meaning that you can upload multiple files to a single URL by using the same URL globbing style supported in the URL, like this:

           	curl --upload-file "{file1,file2}"

          	or even

           	curl -T "img[1-1000].png"

          	When  uploading to an SMTP server: the uploaded data is assumed to be RFC 5322 formatted. It has to feature the necessary set of headers and mail body formatted correctly by the user as curl will not transcode nor encode it further in any way.