Sending HTML mail using a shell script
Asked Answered
B

13

57

How can I send an HTML email using a shell script?

Beachhead answered 23/7, 2010 at 10:6 Comment(7)
What is wrong with the answer that was given, as the mail command is your best option from a shell script? What are you looking for, or where was his answer lacking, that you decided to put a bounty on it?Pavlodar
because i didnt understand the answer well . But all other people can able to understand , but i am not able to do....Beachhead
Then say that. If you don't understand, don't be quiet. Ask for a clarification of the answer.Flocculant
What exactly do you understand and what don't you understand, edit that question with this information.Flocculant
shell send html email - The UNIX and Linux Forums unix.com/shell-programming-scripting/… Sending email from a shell script - Shell Scripting daniweb.com/forums/thread15280.htmlSimp
You already have perfectly good answers to this question. I have no idea how I could give an answer that worked better for you.Et
Readers of answers to this question beware: there are several different programs called mail, for example heirloom-mailx and bsd-mailx on Debian jessie. If a mail command from an answer here doesn't work for you, you're probably using the wrong mail. Refer to your distribution's package manager to install the correct package, and use the specific name of that binary (e.g. bsd-mailx on Debian) to resolve that issue. More details on this here: heirloom.sourceforge.net/mailx_history.htmlCheerleader
S
65

First you need to compose the message. The bare minimum is composed of these two headers:

MIME-Version: 1.0
Content-Type: text/html

... and the appropriate message body:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head><title></title>
</head>
<body>

<p>Hello, world!</p>

</body>
</html>

Once you have it, you can pass the appropriate information to the mail command:

body = '...'

echo $body | mail \
-a "From: [email protected]" \
-a "MIME-Version: 1.0" \
-a "Content-Type: text/html" \
-s "This is the subject" \
[email protected]

This is an oversimplified example, since you also need to take care of charsets, encodings, maximum line length... But this is basically the idea.

Alternatively, you can write your script in Perl or PHP rather than plain shell.

Update

A shell script is basically a text file with Unix line endings that starts with a line called shebang that tells the shell what interpreter it must pass the file to, follow some commands in the language the interpreter understands and has execution permission (in Unix that's a file attribute). E.g., let's say you save the following as hello-world:

#!/bin/sh

echo Hello, world!

Then you assign execution permission:

chmod +x hello-world

And you can finally run it:

./hello-world

Whatever, this is kind of unrelated to the original question. You should get familiar with basic shell scripting before doing advanced tasks with it. Here you are a couple of links about bash, a popular shell:

http://www.gnu.org/software/bash/manual/html_node/index.html

http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html

Stockish answered 23/7, 2010 at 10:27 Comment(9)
can your answer in second part .. I don't know how to use it ?Beachhead
I'm unsure about your question... Are you familiar with shell scripts? Where do you have the information you want to mail?Chiekochien
No i never used shell script .. its just point i need to use it part of my application development ...Beachhead
Email should never be HTML, or indeed anything but plain text. *waves grumpy old man stick*Scarlatti
Some mailx versions (my man page reports Heirloom mailx 12.5 and 12.1 in the two machines I tried it into) do not accept the -a option, as they complain about "ContentType: text/html;: No such file or directory". Instead, the mutt solution below worked like a charm!Infeudation
-a no longer works with this. -a is used for attachments only now.Londalondon
@KraangPrime, What is replacement of -a ?Flyover
@KraangPrime It's not "no longer", it's "in some versions"; there are many incompatible mail implementations. See also https://mcmap.net/q/99229/-how-do-i-send-a-file-as-an-email-attachment-using-linux-command-lineIonic
@GangadharNimballi - that I don't know, and google-fu is failing me right now. Aren't you glad it was updated... cuz newer is better and all that....Londalondon
B
52

The tags include 'sendmail' so here's a solution using that:

(
echo "From: [email protected] "
echo "To: [email protected] "
echo "MIME-Version: 1.0"
echo "Content-Type: multipart/alternative; " 
echo ' boundary="some.unique.value.ABC123/server.xyz.com"' 
echo "Subject: Test HTML e-mail." 
echo "" 
echo "This is a MIME-encapsulated message" 
echo "" 
echo "--some.unique.value.ABC123/server.xyz.com" 
echo "Content-Type: text/html" 
echo "" 
echo "<html> 
<head>
<title>HTML E-mail</title>
</head>
<body>
<a href='http://www.google.com'>Click Here</a>
</body>
</html>"
echo "------some.unique.value.ABC123/server.xyz.com--"
) | sendmail -t

A wrapper for sendmail can make this job easier, for example, mutt:

mutt -e 'set content_type="text/html"' [email protected] -s "subject" <  message.html
Badr answered 26/7, 2010 at 13:47 Comment(5)
what is use of echo "--some.unique.value.ABC123/server.xyz.com"Beachhead
The "--some.unique.value...", which corresponds to the boundary="some.unique.value..." in the headers, is MIME's way of separating multipart messages. When it sees that, it knows that what follows is a new part, and that it should go back to parsing headers. This example is a bit more complicated than it has to be, as the multipart stuff isn't strictly necessary, but it's not a bad idea if you're sending HTML mail.Rinehart
I tested it, and received a blank body. Any idea?Bunns
How would I wrap this command in C++ so that I could run with the system() call?Cannonade
@Cannonade Just open a pipe to sendmail -t and pipe in a well-formatted MIME message.Ionic
K
46

So far I have found two quick ways in cmd linux

  1. Use old school mail

mail -s "$(echo -e "This is Subject\nContent-Type: text/html")" [email protected] < mytest.html

  1. Use mutt

mutt -e "my_hdr Content-Type: text/html" [email protected] -s "subject" < mytest.html

Kirwin answered 7/9, 2012 at 4:4 Comment(9)
This solution is really simple and yet works out of the box. It definitely deserves more upvotes.Sherfield
worked well on MacOSX 10.9. very clever. nice work. any tricks for adding attachments?Floats
@Kevin Zhu: This works, but I doubt its quoting is as you intended. The first double-quote after the -e closes out the double-quote preceding it. I think you meant to do this: "$(echo -e 'This is Subject\nContent-Type: text/html')"Butterfly
The newline in the headers is a hack at best, and was disallowed as an unintended bug with possible security implications in at least one version of mail.Ionic
Thanks to this nice trick! The mail command on mac os x is really simple and crude, I have been searching for whole day and half a night.Thereabout
I'm facing issues when dealing with office 365. Can have a look? #62305571Sachsse
my_hdr what is it reffering to. is it a defined variable for my header ? can it be anything ?Gronseth
@Gronseth gitlab.com/muttmua/mutt/-/wikis/MuttFaq/Header mutt.org/doc/manualKirwin
No, @MikeS, double quotes inside of $( ) work separate from the double quotes outside. Try this example: echo "$(echo "x; echo y")".Antihistamine
A
2

Another option is using msmtp.

What you need is to set up your .msmtprc with something like this (example is using gmail):

account default
host smtp.gmail.com
port 587
from [email protected]
tls on
tls_starttls on
tls_trust_file ~/.certs/equifax.pem
auth on
user [email protected]
password <password>
logfile ~/.msmtp.log

Then just call:

(echo "Subject: <subject>"; echo; echo "<message>") | msmtp <[email protected]>

in your script

Update: For HTML mail you have to put the headers as well, so you might want to make a file like this:

From: [email protected]
To: [email protected]
Subject: Important message
Mime-Version: 1.0
Content-Type: text/html

<h1>Mail body will be here</h1>
The mail body <b>should</b> start after one blank line from the header.

And mail it like

cat email-template | msmtp [email protected]

The same can be done via command line as well, but it might be easier using a file.

Allodial answered 1/8, 2010 at 14:54 Comment(2)
I don't see anything related to HTML mail here, how you define the headers?Slovak
Added myself. Helped me, maybe someone else too.Slovak
T
1

Another option is the sendEmail script http://caspian.dotconf.net/menu/Software/SendEmail/, it also allows you to set the message type as html and include a file as the message body. See the link for details.

Trilley answered 28/7, 2010 at 6:52 Comment(1)
Link no longer works.Yorktown
T
1
cat > mail.txt <<EOL
To: <email>
Subject: <subject>
Content-Type: text/html

<html>
$(cat <report-table-*.html>)
This report in <a href="<url>">SVN</a>
</html>

EOL

And then:

sendmail -t < mail.txt
Tabular answered 8/1, 2015 at 12:22 Comment(2)
might or might not work, depending completely on sendmail used.Slovak
Using a temporary file is unnecessary and inelegant. Just pass in the here document to Sendmail intead of to cat.Ionic
G
1

Using CentOS 7's default mailx (appears as heirloom-mailx), I've simplified this to just using a text file with your required headers and a static boundary for multipart/mixed and multipart/alternative setup.

I'm sure you can figure out multipart/related if you want with the same setup.

test.txt:

--000000000000f3b2150570186a0e
Content-Type: multipart/alternative; boundary="000000000000f3b2130570186a0c"

--000000000000f3b2130570186a0c
Content-Type: text/plain; charset="UTF-8"

This is my plain text stuff here, in case the email client does not support HTML or is blocking it purposely

My Link Here <http://www.example.com>

--000000000000f3b2130570186a0c
Content-Type: text/html; charset="UTF-8"

<div dir="ltr">
<div>This is my HTML version of the email</div>
<div><br></div>
<div><a href="http://www.example.com">My Link Here</a><br></div>
</div>

--000000000000f3b2130570186a0c--
--000000000000f3b2150570186a0e
Content-Type: text/csv; charset="US-ASCII"; name="test.csv"
Content-Disposition: attachment; filename="test.csv"
Content-Transfer-Encoding: base64
X-Attachment-Id: f_jj5qmzqz0

The boundaries define multipart segments.

The boundary ID that has no dashes at the end is a start point of a segment.

The one with the two dashes at the end is the end point.

In this example, there's a subpart within the multipart/mixed main section, for multipart/alternative.

The multipart/alternative method basically says "Fallback to this, IF the priority part does not succeed" - in this example HTML is taken as priority normally by email clients. If an email client won't display the HTML, it falls back to the plain text.

The multipart/mixed method which encapsulates this whole message, is basically saying there's different content here, display both.

In this example, I placed a CSV file attachment on the email. You'll see the attachment get plugged in using base64 in the command below.

I threw in the attachment as an example, you'll have to set your content type appropriately for your attachment and specify whether inline or not.

The X-Attachment-Id is necessary for some providers, randomize the ID you set.

The command to mail this is:

echo -e "`cat test.txt; openssl base64 -e < test.csv`\n--000000000000f3b2150570186a0e--\n" | mailx -s "Test 2 $( echo -e "\nContent-Type: multipart/mixed; boundary=\"000000000000f3b2150570186a0e\"" )" -r [email protected] [email protected]

As you can see in the mailx Subject line I insert the multipart boundary statically, this is the first header the email client will see.

Then comes the test.txt contents being dumped.

Regarding the attachment, I use openssl (which is pretty standard on systems) to convert the file attachment to base64.

Additionally, I added the boundary close statement at the end of this echo, to signify the end of the message.

This works around heirloom-mailx problems and is virtually script-less.

The echo can be a feed instead, or any other number of methods.

Gondi answered 3/7, 2018 at 14:1 Comment(0)
N
0

Mime header and from, to address also can be included in the html file it self.

Command

cat cpu_alert.html | /usr/lib/sendmail -t

cpu_alert.html file sample.

From: [email protected]
To: [email protected]
Subject: CPU utilization heigh
Mime-Version: 1.0
Content-Type: text/html

<h1>Mail body will be here</h1>
The mail body should start after one blank line from the header.

Sample code available here: http://sugunan.net/git/slides/shell/cpu.php

Nacelle answered 19/4, 2015 at 4:59 Comment(1)
Labelling this as an "html file" is misleading. It's an RFC5322 message with an HTML payload.Ionic
S
0

Heres mine (given "mail" is configured correctly):

scanuser@owncloud:~$ vi sendMailAboutNewDocuments.sh

mail -s "You have new mail" -a "Content-type: text/html" -a "From: [email protected]" $1 << EOF
<html>
<body>
Neues Dokument: $2<br>
<a href="https://xxx/index.php/apps/files/?dir=/Post">Hier anschauen</a>
</body>
</html>

EOF

to make executable:

chmod +x sendMailAboutNewDocuments.sh

then call:

./sendMailAboutNewDocuments.sh [email protected] test.doc
Stoa answered 29/6, 2018 at 13:14 Comment(0)
D
0

You can use the option -o in sendEmail to send a html email.

-o message-content-type=html to specify the content type of the email.

-o message-file to add the html file to the email content.

I have tried this option in a shell scripts, and it works.

Here is the full command:

/usr/local/bin/sendEmail -f [email protected] -t "[email protected]" -s \
 smtp.test.com -u "Title" -xu [email protected] -xp password \
 -o message-charset=UTF-8  \
 -o message-content-type=html \
 -o message-file=test.html
Downwash answered 24/7, 2019 at 8:19 Comment(1)
detail description of your answer is necessary.Coot
E
0

I've been trying to just make a simple bash script that emails out html formatted content-type and all these are great but I don't want to be creating local files on the filesystem to be passing into the script and also on our version of mailx(12.5+) the -a parameter for mail doesn't work anymore since it adds an attachment and I couldn't find any replacement parameter for additional headers so the easiest way for me was to use sendmail.

Below is the simplest 1 liner I created to run in our bash script that works for us. It just basically passes the Content-Type: text/html, subject, and the body and works.

printf "Content-Type: text/html\nSubject: Test Email\nHTML BODY<b>test bold</b>" | sendmail <Email Address To>

If you wanted to create an entire html page from a variable an alternative method I used in the bash script was to pass the variable as below.

emailBody="From: <Email Address From>
Subject: Test
Content-Type: text/html; charset=\"us-ascii\"
<html>
<body>
body
<b> test bold</b>

</body>
</html>
"
echo "$emailBody" | sendmail <Email Address To>
Escarpment answered 21/11, 2019 at 15:52 Comment(0)
C
-1

In addition to the correct answer by mdma, you can also use the mail command as follows:

mail [email protected] -s"Subject Here" -a"Content-Type: text/html; charset=\"us-ascii\""

you will get what you're looking for. Don't forget to put <HTML> and </HTML> in the email. Here's a quick script I use to email a daily report in HTML:

#!/bin/sh
(cat /path/to/tomorrow.txt mysql -h mysqlserver -u user -pPassword Database -H -e "select statement;" echo "</HTML>") | mail [email protected] -s"Tomorrow's orders as of now" -a"Content-Type: text/html; charset=\"us-ascii\""
Cutlip answered 15/3, 2011 at 16:4 Comment(1)
Probably there should be a semicolon before mysqlserverIonic
G
-1

The question asked specifically on shell script and the question tag mentioning only about sendmail package. So, if someone is looking for this, here is the simple script with sendmail usage that is working for me on CentOS 8:

#!/bin/sh
TOEMAIL="[email protected]"
REPORT_FILE_HTML="$REPORT_FILE.html"
echo "Subject: EMAIL SUBJECT" >> "${REPORT_FILE_HTML}"
echo "MIME-Version: 1.0" >> "${REPORT_FILE_HTML}"
echo "Content-Type: text/html" >> "${REPORT_FILE_HTML}"
echo "<html>" >> "${REPORT_FILE_HTML}"
echo "<head>" >> "${REPORT_FILE_HTML}"
echo "<title>Best practice to include title to view online email</title>" >> "${REPORT_FILE_HTML}"
echo "</head>" >> "${REPORT_FILE_HTML}"
echo "<body>" >> "${REPORT_FILE_HTML}"
echo "<p>Hello there, you can put email html body here</p>" >> "${REPORT_FILE_HTML}"
echo "</body>" >> "${REPORT_FILE_HTML}"
echo "</html>" >> "${REPORT_FILE_HTML}"

sendmail $TOEMAIL < $REPORT_FILE_HTML
Gronseth answered 15/7, 2020 at 18:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.