Using curl to send email
curl --ssl-reqd \
--url 'smtps://smtp.gmail.com:465' \
--user 'username@gmail.com:password' \
--mail-from 'username@gmail.com' \
--mail-rcpt 'john@example.com' \
--upload-file mail.txt
mail.txt file contents:
From: "User Name" <username@gmail.com>
To: "John Smith" <john@example.com>
Subject: This is a test
Hi John,
I’m sending this mail with curl thru my gmail account.
Bye!
Additional info:
I’m using
curl
version 7.21.6 with SSL support.You don't need to use the
--insecure
switch, which preventscurl
from performing SSL connection verification. See this online resource for further details.It’s considered a bad security practice to pass account credentials thru
command line arguments. Use--netrc-file
. See the documentation.You must turn on access for less secure apps or the newer App passwords.
How to send plain text emails using cURL
If you use the -T
(--upload-file
) option, curl will not issue a VRFY
command.
See https://ec.haxx.se/usingcurl-smtp.html
Example:
curl smtp://mail.example.com --mail-from myself@example.com \
--mail-rcpt receiver@example.com \
--upload-file email.txt
When curl has a message to send, it will not VRFY and instead do MAIL FROM...RCPT TO
.
From man curl
:
--mail-rcpt
(SMTP) Specify a single address, user name or mailing list name.When performing a mail transfer, the recipient should specify a valid email address to send the mail to. (Added in 7.20.0)
When performing an address verification (VRFY command), the recipient should be specified as the user name or user name and
domain (as
per Section 3.5 of RFC5321). (Added in 7.34.0)
It's not very well stated, but if the command is lacking a message (-T
or --upload-file
), then curl performs address verification.
can curl no longer send emails using gmail accounts?
Don't know if will solve your problem, but if you have enabled 2-Step Verification in your Google account, you have to create some app password
Sending an email using curl c++
I found this to be a helpful starting point:
https://curl.se/libcurl/c/smtp-mail.html
There are two main problems with your code:
- Your
read_function
didn't keep track of how much of the payload has been read so it would keep giving the same content to libcurl over and over and never signal the end of the message. - You were setting CURLOPT_MAIL_RCPT to a string when in fact it should be a
struct curl_slist *
because there can be multiple recipients.
Here is a fixed example that I tested on my computer and it worked. Private data at the top of the file was modified before posting.
#define USERNAME "david"
#define PASSWORD "xxxxx"
#define MAILTO "david@example.com"
#define MAILFROM "you@example.com"
#define SMTP "smtp://your.smtp.server.example.com:25"
#include <stdio.h>
#include <curl/curl.h>
const char * payload_text =
"Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n"
"To: " MAILTO "\r\n"
"From: " MAILFROM "\r\n"
"Subject: SMTP example message with libcurl 6\r\n"
"\r\n"
"Hello world!\r\n";
struct ReadData
{
explicit ReadData(const char * str)
{
source = str;
size = strlen(str);
}
const char * source;
size_t size;
};
size_t read_function(char * buffer, size_t size, size_t nitems, ReadData * data)
{
size_t len = size * nitems;
if (len > data->size) { len = data->size; }
memcpy(buffer, data->source, len);
data->source += len;
data->size -= len;
return len;
}
int main()
{
CURL * curl = curl_easy_init();
if (!curl)
{
fprintf(stderr, "curl_easy_init failed\n");
return 1;
}
curl_easy_setopt(curl, CURLOPT_USERNAME, USERNAME);
curl_easy_setopt(curl, CURLOPT_PASSWORD, PASSWORD);
curl_easy_setopt(curl, CURLOPT_URL, SMTP);
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, MAILFROM);
struct curl_slist * rcpt = NULL;
rcpt = curl_slist_append(rcpt, MAILTO);
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, rcpt);
ReadData data(payload_text);
curl_easy_setopt(curl, CURLOPT_READDATA, &data);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_function);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
// If your server doesn't have a proper SSL certificate:
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
return 0;
}
curl : send html email with embedded image and attachment
The solution I came up with is to base64 encode all the attachment (image and text file) and to include them into the uploaded file directly in the multipart/mixed
body such as :
--MULTIPART-MIXED-BOUNDARY
Content-Type: image/png
Content-Transfer-Encoding: base64
Content-Disposition: inline
Content-Id: <admin.png>
iVBORw0KGgoAAAANSUhEUgAAAIAAAACgCAIAAABL8POqAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA
B3RJTUUH4AQNDwEVouBdqAAAG2xJREFUeNrtfX9oHFe25jdDBU5BG25BG7pABhXEkDJjSIsYIs1m
WbfJA8ubhcjjgdiTQNJOYCInj0RKYGIl8CbyPF4iZSCxEkgsB5LIgWQlL2Pcfow3bdgw0mMzox6e
....
--MULTIPART-MIXED-BOUNDARY
Content-Type: text/plain
Content-Transfer-Encoding: base64
Content-Disposition: inline; filename=log.txt
c29tZSBsb2cgaW4gYSB0eHQgZmlsZSB0byBhdHRhY2ggdG8gdGhlIG1haWwK
--MULTIPART-MIXED-BOUNDARY--
The Content-Id
header is used to identify the resource that can be referenced in the html with : cid:
like :
<img src="cid:admin.png" width="150" height="50">
Here is a complete bash
example to send an html email with and admin.png
embedded image and a log.txt
attached to it :
#!/bin/bash
rtmp_url="smtp://smtp.gmail.com:587"
rtmp_from="sender@gmail.com"
rtmp_to="receiver@gmail.com"
rtmp_credentials="sender@gmail.com:secretpassword"
file_upload="data.txt"
# html message to send
echo "<html>
<body>
<div>
<p>Hello, </p>
<p>Please see the log file attached</p>
<p>Admin Team</p>
<img src=\"cid:admin.png\" width=\"150\" height=\"50\">
</div>
</body>
</html>" > message.html
# log.txt file to attached to the mail
echo "some log in a txt file to attach to the mail" > log.txt
mail_from="Some Name <$rtmp_from>"
mail_to="Some Name <$rtmp_to>"
mail_subject="example of mail"
mail_reply_to="Some Name <$rtmp_from>"
mail_cc=""
# add an image to data.txt :
# $1 : type (ex : image/png)
# $2 : image content id filename (match the cid:filename.png in html document)
# $3 : image content base64 encoded
# $4 : filename for the attached file if content id filename empty
function add_file {
echo "--MULTIPART-MIXED-BOUNDARY
Content-Type: $1
Content-Transfer-Encoding: base64" >> "$file_upload"
if [ ! -z "$2" ]; then
echo "Content-Disposition: inline
Content-Id: <$2>" >> "$file_upload"
else
echo "Content-Disposition: attachment; filename=$4" >> "$file_upload"
fi
echo "$3
" >> "$file_upload"
}
message_base64=$(cat message.html | base64)
echo "From: $mail_from
To: $mail_to
Subject: $mail_subject
Reply-To: $mail_reply_to
Cc: $mail_cc
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=\"MULTIPART-MIXED-BOUNDARY\"
--MULTIPART-MIXED-BOUNDARY
Content-Type: multipart/alternative; boundary=\"MULTIPART-ALTERNATIVE-BOUNDARY\"
--MULTIPART-ALTERNATIVE-BOUNDARY
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: base64
Content-Disposition: inline
$message_base64
--MULTIPART-ALTERNATIVE-BOUNDARY--" > "$file_upload"
# add an image with corresponding content-id (here admin.png)
image_base64=$(curl -s "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_116x41dp.png" | base64)
add_file "image/png" "admin.png" "$image_base64"
# add the log file
log_file=$(cat log.txt | base64)
add_file "text/plain" "" "$log_file" "log.txt"
# add another image
#image_base64=$(curl -s "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_116x41dp.png" | base64)
#add_file "image/png" "something.png" "$image_base64"
# end of uploaded file
echo "--MULTIPART-MIXED-BOUNDARY--" >> "$file_upload"
# send email
echo "sending ...."
curl -s "$rtmp_url" \
--mail-from "$rtmp_from" \
--mail-rcpt "$rtmp_to" \
--ssl -u "$rtmp_credentials" \
-T "$file_upload" -k --anyauth
res=$?
if test "$res" != "0"; then
echo "sending failed with: $res"
else
echo "OK"
fi
Related Topics
Linux: Copy and Create Destination Dir If It Does Not Exist
How to Redirect the Output of the Time Command to a File in Linux
Using Awk to Print All Columns from the Nth to the Last
Find and Replace With Sed in Directory and Sub Directories
Better Way to Rename Files Based on Multiple Patterns
What Is Better "Int 0X80" or "Syscall" in 32-Bit Code on Linux
What's the Difference Between Nohup and Ampersand
What Is an Uninterruptible Process
Have Bash Script Answer Interactive Prompts
How to Delete a Newline If It Is the Last Character in a File
What Is the Runtime Performance Cost of a Docker Container
Why Does a Jvm Report More Committed Memory Than the Linux Process Resident Set Size
Is There Any API For Determining the Physical Address from Virtual Address in Linux
How to Determine Whether a Given Linux Is 32 Bit or 64 Bit
How to Use Local Docker Images With Minikube
How to Fix Java.Lang.Module.Findexception: Module Java.Se.Ee Not Found