7

I've been trying to work through sending a html email from mailx on a linux server.

Few Notes:

  • I have to specify a smtp server so therefore I cannot use sendmail (This is not something I can change on my end)
  • I cannot install 3rd party things such as mutt. I will have to use mail or mailx
  • Since my mail/x version is heirloom I do not have the --append or -a (attach header options)
  • not sure if this helps at all but my linux distro is 7.3 (Maipo)

What I've seen in most posts on stackoverflow for my case:

mailx -v -S smtp=SERVER -s "$(echo -e "This is the subject\nContent-Type: text/html")" -r FROM TO < htmlmail.txt

This just returns a plain text email in my case.

So here is what I have tried so far:

Try 1:

I saw in a post to add Content-Disposition: inline.

mailx -v -S smtp=SERVER -s "$(echo -e "This is the subject v1\nContent-Type: text/html\nMIME-Version: 1.0\nContent-Disposition: inline")" -r FROM TO < htmlmail.txt

This ends up sending an html email but since the headers are included inline with the body it outputs as such:

Content-Disposition: inline Message-ID: User-Agent: Heirloom mailx 12.5 7/5/10 MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Hello World

Try 2:

So I do not want the headers printed out in the body. So I tried to remove the Content-Disposition: inline

mailx -v -S smtp=SERVER -s "$(echo -e "This is the subject v2\nContent-Type: text/html\nMIME-Version: 1.0")" -r FROM TO < htmlmail.txt

This ends up sending a plain test email as such:

<html> <b>Hello World</b> </html>

Try 3:

Tried flip flopping content-type and mime-version

mailx -v -S SERVER -s "$(echo -e "This is the subject v3\nMIME-Version: 1.0\nContent-Type: text/html")" -r FROM TO < htmlmail.txt

I ended up receiving no email from this code

Try 4:

I saw online to try another header to help find where the issue lies. So I added the header option to set the mail priority.

mailx -v -S smtp=SERVER -s "$(echo -e "This is a subject v4\nContent-Type: text/html\nX-Priority: 1 (Highest)")" -r FROM TO < htmlmail.txt

This ended up sending a high priority email but all in plain text.

Try 5:

I added on the MIME header to the previous try

mailx -v -S smtp=SERVER -s "$(echo -e "This is a subject v5\nMIME-Version: 1.0\nContent-Type: text/html\nX-Priority: 1 (Highest)")" -r FROM TO < htmlmail.txt

This ended up sending an email with headers in the body and the priority not set to high...weird

X-Priority: 1 (Highest) Message-ID: User-Agent: Heirloom mailx 12.5 7/5/10 MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Hello World

After all of this, I've tried many other adaptations of the above tries but they led to no new output.

So any suggestions or ideas are gladly accepted! Please keep in mind my constraints listed above...I know they limit my options but that's out of my control.

thanks for your time!

2
  • Have a look at this answer on stackoverflow. You should be able to adapt it to send a text/html MIME part instead of a generic attachment. Let me know if you have questions about it. Aug 7, 2017 at 22:06
  • thanks for the suggestion, sadly I cannot use sendmail as I have to specify the smtp server Aug 8, 2017 at 11:42

3 Answers 3

3

First some context: I am using heirloom-mailx version as the one on the following thread: https://serverfault.com/questions/136106/what-package-to-install-for-sending-emails-from-localhost-ubuntu

I am using Ubuntu 16.04 Xenial. Tried also on Ubuntu Server 16.04.

In order to send emails I am using the following function for sending mail using mailx (heirloom mailx in bash):

sendmail() {
#Sending Report Email
heirloom-mailx -a $2 -v -s ""$(echo -e "subject 3\nContent-Type: text/html")"" \
-S smtp-use-starttls \
-S ssl-verify=ignore \
-S smtp-auth=login \
-S smtp=smtp://mail.mymailserver:port \
-S from="[email protected]" \
-S [email protected] \
-S smtp-auth-password='password' \
-S ssl-verify=ignore \
$1 < body.html
}

Where $2 is the attachment and $1 is the destination. Notes: 1. Files attached are printed inside the body as well but this could be useful to you if you wish just to send an html file with no attachments. 2. Using "-v" option prints verbose so you might get an issue with .mime.types that can be ignored. Remove the option if you don't want verbose on mailx. 3. You will still get the following in the body if you use the "-a" option: This is a multi-part message in MIME format. --=-=fFPa7dLqoSF1TGj-YDc2k8bdvmjpix_4sKFT=-= Content-Type: text/plain; charset=US-ASCII Content-Disposition: inline

In this case I am attaching a plain text file. Removing "-a $2" from the command and you are all set to print the html message. So the final result would be:

sendmail() {
    #Sending Report Email
    heirloom-mailx -s ""$(echo -e "subject 3\nContent-Type: text/html")"" \
    -S smtp-use-starttls \
    -S ssl-verify=ignore \
    -S smtp-auth=login \
    -S smtp=smtp://mail.mymailserver:port \
    -S from="[email protected]" \
    -S [email protected] \
    -S smtp-auth-password='password' \
    -S ssl-verify=ignore \
    $1 < body.html
    }

Try it out and let me know. I have tested on my end and it works.

6
  • 1
    The $(echo -e "stuff\nwith\nnewlines") is just a roundabout, inefficient, nonportable way of specifying a string with literal newlines. I can't show that in a comment, but the Bourne shell lets you say literally "stuff(newline)with(newline)newlines" between single or double quotes. Bash also has $'C-style\nstrings'.
    – tripleee
    Dec 27, 2019 at 7:30
  • 1
    It should also be noted that this has been regarded as a security vulnerability in (other versions of?) mailx and might stop working in the future.
    – tripleee
    Dec 27, 2019 at 8:04
  • @tripleee if you have a better solution please provide it. Jan 3, 2020 at 10:29
  • Being able to use direct mail injection with mailx but not being allowed to install a proper MTA seems to be a rather esoteric scenario. I would definitely suggest using a different MUA if you can.
    – tripleee
    Jan 3, 2020 at 10:31
  • @tripleee this is not an actual solution to his problem, is it now? If you can improve on my answer I would like to read on your solution see where I can improve but take into account the constraints of the question and what is requested. Jan 3, 2020 at 10:36
1

If you are stuck on a server where you can't install new software, including a proper MTA, perhaps the simplest workaround is to write a simple script in a language which has libraries for SMTP included. My choice would be Python. Here is a simple adaptation of example code from the documentation.

#!/usr/bin/env python3

import smtplib
from argparse import ArgumentParser
from email.message import EmailMessage


def main():
    parser = ArgumentParser(description="""\
Quick and dirty mailx replacement for sending a HTML message via a
specific SMTP server. Based on examples from
https://docs.python.org/3/library/email.examples.html#email-examples
""")
    parser.add_argument('-H', '--html-file', required=True,
                        help="The HTML body to send (required)")
    parser.add_argument('-S', '--smtp-server', required=True,
                        help='The SMTP server to use (required)')
    parser.add_argument('-s', '--subject', required=True,
                        help='Subject (required)')
    parser.add_argument('-r', '--return-path', required=True,
                        help='Return-Path / envelope sender (required)')
    parser.add_argument('recipients', nargs='+')
    args = parser.parse_args()

    msg = EmailMessage()
    msg['Subject'] = args.subject
    msg['To'] = ', '.join(args.recipients)
    msg['From'] = args.return_path
    # The examples suggest you should mess with the preamble, but you should not

    with open(args.html_file, 'r') as html:
        msg.set_content(html.read(), subtype='html')

    with smtplib.SMTP(args.smtp_server) as s:
        s.send_message(msg)


if __name__ == '__main__':
    main()

Usage:

python3 path/to/script.py -S SERVER -s "This is the subject" \
    -r FROM -H htmlmail.html TO

This targets Python version 3. If you are on a legacy platform, maybe you only have Python 2; but it should be fairly obvious how to adapt this (mainly use the email.message.Message legacy class instead of the overhauled and modernized EmailMessage introduced in 3.3 and made official in 3.5).

1
  • Sorry about the design with so many non-optional options. Some of the blame will lay on the mailx options where I opted to copy their semantics.
    – tripleee
    Jan 7, 2020 at 7:25
0

I just figured it out, back to your first case, when you injected your header into the subject field, you pushed the header made by mailx (the one that says plaintext) into the body. This means that, it thinks your body started at the end of your real header, taking the pushed header in. This means you can use HTML to solve your problem.

At the end of your injected header, put

<html><!--

This starts an html comment!

In the start of your real, intended body, put

-->

to close the comment! This hides the pushed header away from the body!

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .