Send HTML message with attachement (.pdf) from Shell - shell

I understood how I can send a HTML message with sendmail doing:
(
echo "From: me#example.com";
echo "To: you#example.com";
echo "Subject: this is my subject";
echo "Content-Type: text/html";
echo "MIME-Version: 1.0";
echo "";
echo "My <b>HTML message<\b> goes here!";
) | sendmail -t
I also manages to send an attachement with mail doing
uuencode file.pdf file.pdf | mail -s "my subject" you#example.com
but I fail to send an HTML message with an attachement (.pdf).
Note that I failed to install mutt or mpack (using homebrew) so far so I would love a solution that works with mail, mailx or sendmail. I am on Mac OS X 10.11

What you need to do is use multipart mime.
Your Content-Type should be something like:
Content-Type: multipart/mixed; boundary=multipart-boundary
Your multipart-boundary can be any string you like.
Then you output a line "--multipart-boundary" followed by headers, then body for each part.
For example:
--multipart-boundary
Content-Type: text/html
My <b>HTML message<\b> goes here!
--multipart-boundary
Content-Type: application/pdf
Content-Disposition: attachment; filename=file.pdf
Content-Transfer-Encoding: base64
**cat your base64 encoded file here **
--multipart-boundary--
The extra two dashes at the end mark the end of last part. You can add as many attachments as you like.

Related

Unable to send mail when trying to get mail recipient from a file outside the script in the same dir

I use the code below and it's working fine.
dl=xyz#somebody.com
mail -t $dl << EOM
Subject: Report Status $(date)
Content-Type: text/html
mail text
EOM
However, when I try to get the mail id from file dl.txt, no mail is sent.
dl='/script/user/dl.txt'
mail -t $(echo cat $dl) << EOM
subject: Report Status $(date)
content-Type: text/html
mail text
EOM
Note: text file contains mail ids.
If you try to run
dl='/script/user/dl.txt'
echo cat $dl
The output will be
cat /script/user/dl.txt
Remove echo or better change code like this
to=$(cat '/script/user/dl.txt')
mail -t $to << EOM
Subject: Report Status $(date)
Content-Type: text/html
mail text
EOM

Portable way of programmatically sending an e-mail with an attachment under Unix

I wish to have a portable Unix way of programmatically sending an e-mail with an attachment. The "standard" Unix way of sending an e-mail seems to be mail(1), but there seems to be no portable way of specifying an attachment. (Yes, I know that some versions of mail(1) have an -a or an -A option, but that's not standard, so I cannot rely on it.)
I'll be using ruby for this, but I want a generic solution, i.e., a special ruby configuration involving (say) using Net::SMTP and specifying details like the SMTP server &c. should not be in the application, but the application should issue a command like mail <some other stuff here> and from there the system should deliver the mail (with a suitable ~/.mailrc or whatever).
mail command will work only if it can find a SMTP host. There is a number of ways it can be done (sSMTP, Postfix, sendmail). The most "normal" way is to have sendmail running on your computer, which means localhost itself is an SMTP server. I don't know of a way of getting the SMTP configuration automatically if you don't have sendmail installed.
Therefore, assuming you know the SMTP server (localhost in this example), from Tutorials Point a pure Ruby mail attachment:
require 'net/smtp'
filename = "/tmp/test.txt"
# Read a file and encode it into base64 format
filecontent = File.read(filename)
encodedcontent = [filecontent].pack("m") # base64
marker = "AUNIQUEMARKER"
body = <<EOF
This is a test email to send an attachement.
EOF
# Define the main headers.
part1 = <<EOF
From: Private Person <me#fromdomain.net>
To: A Test User <test#todmain.com>
Subject: Sending Attachement
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary = #{marker}
--#{marker}
EOF
# Define the message action
part2 = <<EOF
Content-Type: text/plain
Content-Transfer-Encoding:8bit
#{body}
--#{marker}
EOF
# Define the attachment section
part3 = <<EOF
Content-Type: multipart/mixed; name = \"#{filename}\"
Content-Transfer-Encoding:base64
Content-Disposition: attachment; filename = "#{filename}"
#{encodedcontent}
--#{marker}--
EOF
mailtext = part1 + part2 + part3
# Let's put our code in safe area
begin
Net::SMTP.start('localhost') do |smtp|
smtp.sendmail(mailtext, 'me#fromdomain.net', ['test#todmain.com'])
end
rescue Exception => e
print "Exception occured: " + e
end

curl : send html email with embedded image and attachment

My goal is to send an email using curl with an html body with embedded image such as :
I'm sending the email like this :
curl "smtp://smtp.gmail.com:587" -v \
--mail-from "sender#gmail.com" \
--mail-rcpt "receiver#gmail.com" \
--ssl -u sender#gmail.com:secretpassword \
-T "message.txt" -k --anyauth
My message.txt looks like :
From: Some Name <sender#gmail.com>
To: Some Name <receiver#gmail.com>
Subject: example of mail
Reply-To: Some Name <sender#gmail.com>
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
PGh0bWw+Cjxib2R5PgogICAgPGRpdj4KICAgICAgICA8cD5IZWxsbywgPC9wPgogICAgICAgIDxw
PlBsZWFzZSBzZWUgdGhlIGxvZyBmaWxlIGF0dGFjaGVkPC9wPgogICAgICAgIDxwPkFkbWluIFRl
YW08L3A+CiAgICAgICAgPGltZyBzcmM9ImFkbWluLnBuZyIgd2lkdGg9IjE1MCIgaGVpZ2h0PSI1
MCI+CiAgICA8L2Rpdj4KPC9ib2R5Pgo8L2h0bWw+Cg==
--MULTIPART-ALTERNATIVE-BOUNDARY--
--MULTIPART-MIXED-BOUNDARY
The html decoded is :
<html>
<body>
<div>
<p>Hello, </p>
<p>Please see the log file attached</p>
<p>Admin Team</p>
<img src="admin.png" width="150" height="50">
</div>
</body>
</html>
How can I embed admin.png in this html and attach another file log.txt
to this email using curl and bash ?
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
Here's a shell script you could use.
I heavily derived from https://blog.ambor.com/2021/08/using-curl-to-send-e-mail-with.html
Passwords could be stored in a .netrc file as discussed on: https://everything.curl.dev/usingcurl/netrc but I haven't tried that.
Just make sure the image you need is embedded in the HTML using base64 encoding.
#!/bin/bash
declare -a VOPTS;
declare -a HOPTS;
sesAccess="sender.account.authentication#email.id" ;
sesSecret="sender.account.passwordXXXXXX";
sesFromName="Sender Full Name";
sesFromAddress='<sender#email.id>';
sesToName="Recipient Full Name";
sesToAddress="<recepient#email.id>"
sesSubject="Email Subject Line";
sesSMTP='mail.server.fqdn';
sesPort='465';
sesMessage=$'Test of line 1\nTest of line 2'
sesFile="$1"; # attachment is first argument
sesHTMLbody="/path/to/html/file.html"; # content of this file will be used to create HTML body
sesMIMEType=`file --mime-type "$sesFile" | sed 's/.*: //'`;
# sesMIMEType=`file -b --mime-type "$sesFile"`;
VOPTS=();
HOPTS=();
#Curl Options
VOPTS+=("-v");
VOPTS+=("--url"); VOPTS+=("smtps://$sesSMTP:$sesPort");
VOPTS+=("--ssl-reqd")
VOPTS+=("--user"); VOPTS+=("${sesAccess}:${sesSecret}");
VOPTS+=("--mail-from"); VOPTS+=("${sesFromAddress}");
VOPTS+=("--mail-rcpt"); VOPTS+=("${sesToAddress}");
#Header Options
HOPTS+=("-H"); HOPTS+=("Subject: ${sesSubject}");
HOPTS+=("-H"); HOPTS+=("From: ${sesFromName} ${sesFromAddress}");
HOPTS+=("-H"); HOPTS+=("To: ${sesToName} ${sesToAddress}");
curl "${VOPTS[#]}" -F '=(;type=multipart/mixed' -F "=<$sesHTMLbody;type=text/html;encoder=base64" -F "file=#$sesFile;type=$sesMIMEType;encoder=base64" -F '=)' "${HOPTS[#]}"
exit
Plus one, your code example is a bit misleading tough, in fact it doesn't work.
As you say, you just have to enclose each part in a boundary, in your case the delimiter is:
"--MULTIPART-MIXED-BOUNDARY".
Nonetheless it could be any other user defined string.
You are nesting multiple boundary types, which isn't necessary. HTML content doesn't need to be base64 encoded, it can go encoded if you will though.
You need a blank line after and before each delimiter.
I recommend taking a look at the W3 papers and examples: https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
The answer by #bertrand-martel was mostly right on my system running Ubuntu 22.04 and submitting to a postfix server in my network. The html email message came through just fine, and I had empty attachments named correctly. I had to edit the add_file function he defined and add in a blank line before the $3 at the very end. The email would not work without a blank line between the Content-Disposition: and the base64 encoding. I also had to insert a blank line after the --MULTIPART-ALTERNATIVE-BOUNDARY--
. Once I made those changes, the html message, the embedded image, and the attached file all came across correctly.

How to send a mail with special characters as subject by using sendmail command in unix shell script

In my script i want to send a mail with some subject, some text as body along with csv file as attachement
My problem is subject has special characters in portuguese language
like this
Subject: Relatório de utilização do QRCODE
i am using sendmail command to send mail because i need to change sender name(not email id)
I tried this :
Subject=Relatório de utilização do QRCODE
mnth=$(date '+%m/%Y' --date="1 month ago")
echo 'mês:'$mnth>>mailBody.html
echo 'contagem de registros:'11090>>mailBody.html
cat mailBody.html>out.mail
echo "$mnth"
uuencode QR_Log.csv QR_Report_$fname.csv >> out.mail
sendmail -F "xyzname" "$subject" -f "receiver#abc.com" <out.mail
echo "mail sent"
when i run the above script i am getting message like this :
Syntax error in mailbox address "Relat??rio.de.utiliza????o.do.QRCODE"
(non-printable character)
mail sent
How can i achieve this please Help me...
Help is very much appreciated. I'll just wait
Thanks in advance
I wrote a shell script like this and I got a valid title. Try to rewrite the code for sending mail like MIME:
#!/bin/bash
echo 'To: you#domain.net'>>test.html
echo 'From: Some User <user#domain.net>'>>test.html
echo 'Subject: Relatório de utilização do QRCODE'>>test.html
echo 'MIME-Version: 1.0'>>test.html
echo 'Content-Type: text/html; charset="utf-8"'>>test.html
echo 'Content-Disposition: inline'>>test.html
echo ''>>test.html
echo '<span style="color:red;">Your message goes here</span>'>>test.html
sendmail -i -t < test.html
rm test.html
Let me know if this helped :)
Below is my old answer...
Not a linux guy but this may help you. First you must encode the subject to base64. For example:
echo 'your subject' | openssl base64
Let's say you've put the encoded string into $subject variable. Next you set the subject like this when sending email:
"=?UTF-8?B?$subject?="
Basically try to put =?UTF-8?B? before the base64-encoded subject and ?= after it without spaces.
As I said I'm not too much of a linux guy but you'll manage :)
Let me know if it helped.
rfc2045 - (5) (Soft Line Breaks) The Quoted-Printable encoding REQUIRES that encoded lines be no more than 76 characters long.
For bash shell script code:
#!/bin/bash
subject_encoder(){
echo -n "$1" | xxd -ps -c3 |awk -Wposix 'BEGIN{
BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
printf " =?UTF-8?B?"; bli=8
}
function encodeblock (strin){
b1=sprintf("%d","0x" substr(strin,1,2))
b2=sprintf("%d","0x" substr(strin,3,2))
b3=sprintf("%d","0x" substr(strin,5,2))
o=substr(BASE64,b1/4 + 1,1) substr(BASE64,(b1%4)*16 + b2/16 + 1,1)
len=length(strin)
if(len>1) o=o substr(BASE64,(b2%16)*4 + b3/64 + 1,1); else o=o"="
if(len>2) o=o substr(BASE64,b3%64 +1 ,1); else o=o"="
return o
}{
bs=encodeblock($0)
bl=length(bs)
if((bl+bli)>64){
printf "?=\n =?UTF-8?B?"
bli=bl
}
printf bs
bli+=bl
}END{
printf "?=\n"
}'
}
SUBJECT="Relatório de utilização"
SUBJECT=`subject_encoder "${SUBJECT}"`
echo '<html>test</html>'| mail -a "Subject:${SUBJECT}" -a "MIME-Version: 1.0" -a "Content-Type: text/html; charset=UTF-8" you#domain.net

Send e-mail with multiple attachments using command line and sendmail

Is it possible to send multiple attachments with uuencode and sendmail?
In a script I have a variable containing the files that need to be attached to a single e-mail like:
$attachments=attachment_1.pdf attachment_2.pdf attachment_3.pdf attachment_4.pdf
Also a $template variable like:
$template="Subject: This is the subject
From: no-reply#domain.com
To: %s
Content-Type: text/plain
This is the body.
"
I have come up with:
printf "$template" "$recipient" |
sendmail -oi -t
Somewhere within this I must attach everything in the $attachments variable?
uuencode attachemnts and send via sendmail
Sending MIME attachemnts is better.
uuencode is simpler to implement in scripts but email some clients DO NOT support it.
attachments="attachment_1.pdf attachment_2.pdf attachment_3.pdf attachment_4.pdf"
recipient='john.doe#example.net'
# () sub sub-shell should generate email headers and body for sendmail to send
(
# generate email headers and begin of the body asspecified by HERE document
cat - <<END
Subject: This is the subject
From: no-reply#domain.com
To: $recipient
Content-Type: text/plain
This is the body.
END
# generate/append uuencoded attachments
for attachment in $attachments ; do
uuencode $attachment $attachment
done
) | /usr/sbin/sendmail -i -- $recipient
For what its worth, mailx also works well.
mailx -s "Subject" -a attachment1 -a attachement2 -a attachment3 email.address#domain.com < /dev/null

Resources