How can I send an HTML email using a shell script?
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 fromaddress@example.com toaddress@example.com
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.