Repository: awdeorio/mailmerge

Issue:
Content-Type gets overwritten to text/plain with attachment
Template:

```
From: a@example.invalic
TO: b@example.invalic
SUBJECT: Hello
ATTACHMENT: a.txt
CONTENT-TYPE: text/html

<html>
<body>
<p>Hi,</p>
</body>
</html>

```

command: `mailmerge --database database.csv --template 04.tpl  --output-format raw`

output:


```
>>> message 1
Content-Type: multipart/alternative;
 boundary="===============1872202902524908882=="
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
SUBJECT: Hello
From: a@example.invalic
TO: b@example.invalic
Date: Wed, 05 Aug 2020 21:37:21 -0000

--===============1872202902524908882==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

<html>
<body>
<p>Hi,</p>
</body>
</html>
--===============1872202902524908882==
Content-Type: application/octet-stream; Name="a.txt"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="a.txt"

aGVsbG93b3JsZA==

--===============1872202902524908882==--
>>> message 1 sent
>>> Limit was 1 message.  To remove the limit, use the --no-limit option.
>>> This was a dry run.  To send messages, use the --no-dry-run option.
```

The important part being `Content-Type: text/plain; charset="us-ascii"`, which is incorrect. Using a [html+plaintext](https://github.com/awdeorio/mailmerge#html-and-plain-text) message works, but that is more complicated.

Discussion:

Patch:
diff --git a/mailmerge/template_message.py b/mailmerge/template_message.py
index 135bba8..9a12fc4 100644
--- a/mailmerge/template_message.py
+++ b/mailmerge/template_message.py
@@ -115,9 +115,11 @@ class TemplateMessage(object):
 
         # Copy text, preserving original encoding
         original_text = self._message.get_payload(decode=True)
+        original_subtype = self._message.get_content_subtype()
         original_encoding = str(self._message.get_charset())
         multipart_message.attach(email.mime.text.MIMEText(
             original_text,
+            _subtype=original_subtype,
             _charset=original_encoding,
         ))
 


Test patch:
diff --git a/tests/test_template_message.py b/tests/test_template_message.py
index 346975f..621a2bd 100644
--- a/tests/test_template_message.py
+++ b/tests/test_template_message.py
@@ -611,7 +611,7 @@ def test_attachment_multiple(tmp_path):
 
 
 def test_attachment_empty(tmp_path):
-    """Errr on empty attachment field."""
+    """Err on empty attachment field."""
     template_path = tmp_path / "template.txt"
     template_path.write_text(textwrap.dedent(u"""\
         TO: to@test.com
@@ -626,6 +626,75 @@ def test_attachment_empty(tmp_path):
         template_message.render({})
 
 
+def test_contenttype_attachment_html_body(tmpdir):
+    """
+    Verify that the content-type of the message is correctly retained with an
+    HTML body.
+    """
+    # Simple attachment
+    attachment_path = Path(tmpdir/"attachment.txt")
+    attachment_path.write_text(u"Hello world\n")
+
+    # HTML template
+    template_path = Path(tmpdir/"template.txt")
+    template_path.write_text(textwrap.dedent(u"""\
+        TO: to@test.com
+        FROM: from@test.com
+        ATTACHMENT: attachment.txt
+        CONTENT-TYPE: text/html
+
+        Hello world
+    """))
+
+    # Render in tmpdir
+    with tmpdir.as_cwd():
+        template_message = TemplateMessage(template_path)
+        _, _, message = template_message.render({})
+
+    # Verify that the message content type is HTML
+    payload = message.get_payload()
+    assert len(payload) == 2
+    assert payload[0].get_content_type() == 'text/html'
+
+
+def test_contenttype_attachment_markdown_body(tmpdir):
+    """
+    Verify that the content-types of the MarkDown message are correct when
+    attachments are included.
+    """
+    # Simple attachment
+    attachment_path = Path(tmpdir/"attachment.txt")
+    attachment_path.write_text(u"Hello world\n")
+
+    # HTML template
+    template_path = Path(tmpdir/"template.txt")
+    template_path.write_text(textwrap.dedent(u"""\
+        TO: to@test.com
+        FROM: from@test.com
+        ATTACHMENT: attachment.txt
+        CONTENT-TYPE: text/markdown
+
+        Hello **world**
+    """))
+
+    # Render in tmpdir
+    with tmpdir.as_cwd():
+        template_message = TemplateMessage(template_path)
+        _, _, message = template_message.render({})
+
+    # Markdown: Make sure there is a plaintext part and an HTML part
+    payload = message.get_payload()
+    assert len(payload) == 3
+
+    # Ensure that the first part is plaintext and the second part
+    # is HTML (as per RFC 2046)
+    plaintext_part = payload[0]
+    assert plaintext_part['Content-Type'].startswith("text/plain")
+
+    html_part = payload[1]
+    assert html_part['Content-Type'].startswith("text/html")
+
+
 def test_duplicate_headers_attachment(tmp_path):
     """Verify multipart messages do not contain duplicate headers.