81

mail -s "subject" xxxxx@gmail.com <test.html works, but only for plain text email.

What is the correct way to send HTML email using the Linux command mail?

pyth0ner
  • 911
  • The scripts here are fine for simple English text with short lines, but proper MIME support requires you to handle non-ASCII character sets and arbitrarily long lines by wrapping them properly. In short, you can assemble a valid MIME structure with echo and cat, but for many real-world scenarios, you really really don't want to. – tripleee Nov 03 '22 at 12:35

9 Answers9

74

There are many different versions of mail around. When you go beyond mail -s subject to1@address1 to2@address2 <body (for sending, that's all POSIX guarantees — and even -s didn't exist in the old days), they tend to have different command line options. Adding an additional header isn't always easy.

  • With some mailx implementations, e.g. from mailutils on Ubuntu or Debian's bsd-mailx, it's easy, because there's an option for that.

    mailx -a 'Content-Type: text/html' -s "Subject" to@address <test.html
    
  • With the Heirloom mailx, there's no convenient way. One possibility to insert arbitrary headers is to set editheaders=1 and use an external editor (which can be a script).

    ## Prepare a temporary script that will serve as an editor.
    ## This script will be passed to ed.
    temp_script=$(mktemp)
    cat <<'EOF' >>"$temp_script"
    1a
    Content-Type: text/html
    .
    $r test.html
    w
    q
    EOF
    ## Call mailx, and tell it to invoke the editor script
    EDITOR="ed -s $temp_script" heirloom-mailx -S editheaders=1 -s "Subject" to@address <<EOF
    ~e
    .
    EOF
    rm -f "$temp_script"
    
  • With a general POSIX mailx, I don't know how to get at headers.

If you're going to use any mail or mailx, keep in mind that

  • This isn't portable even within a given Linux distribution. For example, both Ubuntu and Debian have several alternatives for mail and mailx.
  • When composing a message, mail and mailx treats lines beginning with ~ as commands. If you pipe text into mail, you need to arrange for this text not to contain lines beginning with ~.

If you're going to install software anyway, you might as well install something more predictable than mail/Mail/mailx. For example, mutt. With Mutt, you can supply most headers in the input with the -H option, but not Content-Type, which needs to be set via a mutt option.

mutt -e 'set content_type=text/html' -s 'hello' 'to@address' <test.html

Or you can invoke sendmail directly. There are several versions of sendmail out there, but they all support sendmail -t to send a mail in the simplest fashion, reading the list of recipients from the mail. (I think they don't all support Bcc:.) On most systems, sendmail isn't in the usual $PATH, it's in /usr/sbin or /usr/lib.

cat <<'EOF' - test.html | /usr/sbin/sendmail -t
To: to@address
Subject: hello
Content-Type: text/html

EOF
  • Tried using the mutt example above; substituting real values for the filename, to email address, etc. but got "No recipients were specified" I'm very new to mutt, @Gilles do you know why that might have happened? (osx mountain lion, mutt 1.5.21 installed via homebrew) – Chuck van der Linden Jul 15 '13 at 16:58
  • my second line was "To: myaddress@mycompany.com" (sorry for lack of formatting, not possible in a response, actual text was sans quotes) and I included a blank line before putting in the EOF. would there be configuration I need to do to mutt? prior to trying the example you gave (with proper values substituted) all I did was 'brew install mutt' – Chuck van der Linden Jul 15 '13 at 19:10
  • @ChuckvanderLinden Ask a new question. Copy-paste the exact command you ran and the full error message. See if you can send an email from mutt using the interactive interface. – Gilles 'SO- stop being evil' Jul 15 '13 at 19:15
  • I was able to send something via the 'interactive' interface, it initially complained about a mail directory missing and offered to create it. reminded how much I hate vim ;-) but got it to send. I'll start a new question as that is easier to format etc. The exact error message was just what I said "No recipients were specified." – Chuck van der Linden Jul 15 '13 at 19:45
  • New question http://unix.stackexchange.com/questions/83137/trying-to-send-html-mail-on-mac-osx-mountain-lion – Chuck van der Linden Jul 15 '13 at 20:06
16
#!/bin/sh

(
echo "To: me@example.com"
echo "Subject: hello"
echo "Content-Type: text/html"
echo
echo "<html><b><font size='7'>H</font>ello</b></html>"
echo
) | /usr/sbin/sendmail -t
Code Improver
  • 161
  • 1
  • 2
7

With the Heirloom mailx, convenient way is

mailx -s "$(echo -e "Newsletter issue 3\nContent-Type: text/html")" user@server.com < /tmp/htmlmail.txt

Thanks, Dude
Tested on Fedora 17, and worked

daniel
  • 79
4

You will have to add Content-Type header to your email to make this happen.

echo "<html><b>Hello</b></html>" | mail -a "Content-type: text/html;" -s "Testing" me@example.com

will work

  • 3
    mail: illegal option -- a – pyth0ner Jun 22 '11 at 06:56
  • Do you have mailx? That might have the option. If that doesn't work. If that doesn't work, you can consider using mutt although I don't know off hand what the command line switches to do it are. – Noufal Ibrahim Jun 22 '11 at 07:04
  • 1
    if mail isn't cutting the mustard, use python ... http://docs.python.org/library/email-examples.html examples is the 3rd one or #6 which suits your requirement. – sdolgy Jun 22 '11 at 08:40
  • Python will require you to write (and maintain) a script. A command line one liner has different advantages. – Noufal Ibrahim Jun 22 '11 at 11:04
  • I have mailx,but "option -a" don't work,still show:mail: illegal option -- a – pyth0ner Jun 27 '11 at 01:17
  • I have the mail command in Arch Linux provided by the s-nail package, and the -a option is entirely different. – trusktr Feb 12 '14 at 03:23
  • The Debian/Ubuntu package that provides mail with a -a option is bsd-mailx. Doesn't support attachments though. – Alastair Irvine Nov 16 '16 at 16:29
3

With heirloom-mailx you can change sendmail program to your hook script, replace headers there and then use sendmail.

The script I use (~/bin/sendmail-mailx-hook):

#!/bin/bash

sed '1,/^$/{
s,^\(Content-Type: \).*$,\1text/html; charset=utf-8,g
s,^\(Content-Transfer-Encoding: \).*$,\18bit,g
}' | sendmail $@

This script changes the values in the mail header as follows:

  • Content-Type: to text/html; charset=utf-8
  • Content-Transfer-Encoding: to 8bit (not sure if this is really needed).

To send HTML email:

mailx -Ssendmail='~/bin/sendmail-mailx-hook' -s "subject" xxxxx@gmail.com < test.html

This method is more effective than proposed by @Gilles because it does not create temporary files and just fix the stream on-the-fly.

loentar
  • 143
  • 6
2

I have used the below scripts to happen

#!/bin/ksh

(
echo "To: yourmail@domain.com"
echo "Subject: Job Status"
echo "Content-Type: text/html"
echo
echo "<html>
<head>
<title>Status of the jobs during the day</title>
<style>
table, th, td {
    border: 1px solid blue;
    border-collapse: collapse;
}
th, td {
    padding: 5px;
}
</style>
</head>
<body>
<table style='width:100%'>
<tr bgcolor='#808080'>
    <th>Job Name</th>
    <th>System name</th>
    <th>Status</th>
  </tr>
  <tr>
    <td>Job-1</td>
    <td>Sys</td>
    <td>Sucess</td>
  </tr>
  <tr>
    <td>Job-2</td>
    <td>sys</td>
    <td>Failure</td>
  </tr>
  <tr>
    <td>Job-3</td>
    <td>sys</td>
    <td>Sucess</td>
  </tr>
 </table>
</body></html>"
echo
) | /usr/sbin/sendmail -t
don_crissti
  • 82,805
  • Nothing here is specific to ksh; you could change the shebang to #!/bin/sh. The path to sendmail differs between platforms; probably take it out and rely on your PATH instead (and/or check in /usr/libexec and some other peculiar places). – tripleee Nov 03 '22 at 12:31
0

For me i needed to specify a variable such as SMTP server, so the mail command worked in the below fashion. I searched across many posts, and i found below property to convert the body into text/html. Now the email i receive is in the HTML format.

Content-Disposition: inline

Unix version: Red Hat Enterprise Linux Server release 6.6 (Santiago)

First. Create whatever information is needed into a script (testSql.sh)

echo "<html><body><pre>"
mysql -u USERNAME -pPASSWORD -P PORTNUMBER -h HOSTNAME DBNAME --table -e "select columns from tablename where member in ('value1','value2')"
echo "</pre></body></html>"

Second. Pipe that script to the mail command

./testSql.sh  | mail -v -S smtp=smtp://IP:PORTNUMBER -s "$(echo -e "This is the subject\nContent-Type: text/ht ml\nMIME-Version: 1.0\nContent-Disposition: inline")" userid@email.com

By doing this i get information as below in the email:

Content-Disposition: inline Message-ID: User-Agent: Heirloom mailx 12.4 7/29/08 MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit 

Value1 Value2

Value1 and Value2 as per the HTML tagging done in the testSql.sh

Anthon
  • 79,293
Naga
  • 1
0

Posted in another thread but basically on our version of mail/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 a simple 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>
Miburi
  • 101
  • 1
-5
cat htmlfile.html | mail -s "subject" xx@example.com