Repository: sendgrid/sendgrid-python

Issue:
text/plain must precede text/html content
#### Issue Summary

Requests to send mail with both plain text and HTML content fail if the HTML content is specified first.

#### Code

```
sg = sendgrid.SendGridAPIClient(apikey=sendgrid_key)
mail = Mail()
from_email = Email("from@email.com")
to_email = Email("to@email.com")
subject = "Sending with SendGrid is Fun"
per = Personalization()
mail.from_email = from_email
mail.subject = subject
html_content = Content("text/html", "<html><body>some text here</body></html>")
plain_content = Content("text/plain", "and easy to do anywhere, even with Python")

### Add plain content first
mail.add_content(plain_content)

### Add HTML content next
mail.add_content(html_content)

per.add_to(to_email)
mail.add_personalization(per)
response = sg.client.mail.send.post(request_body=mail.get())
```



#### Steps to Reproduce

1. The above code works properly, but if you reverse the order of the add_content lines, http-client throws a BadRequestsError

#### Expected Result

The library should sort content into the order that the API expects. (I'm not clear why the order should matter to the API—perhaps this should be fixed there instead.)

#### Technical details:

* sendgrid-python Version: master (latest commit: [b12728a53d4c997832c56289c7559f22acf1ff90])
* Python Version: 2.7.13

Discussion:

Patch:
diff --git a/sendgrid/helpers/mail/mail.py b/sendgrid/helpers/mail/mail.py
index 116afb4..7d131f4 100644
--- a/sendgrid/helpers/mail/mail.py
+++ b/sendgrid/helpers/mail/mail.py
@@ -293,7 +293,14 @@ class Mail(object):
 
         :type content: Content
         """
-        self._contents.append(content)
+        if self._contents is None:
+            self._contents = []
+        
+        # Text content should be before HTML content
+        if content._type == "text/plain":
+            self._contents.insert(0, content)
+        else:
+            self._contents.append(content)
 
     @property
     def attachments(self):


Test patch:
diff --git a/test/test_mail.py b/test/test_mail.py
index 8b88f5b..0941fa7 100644
--- a/test/test_mail.py
+++ b/test/test_mail.py
@@ -68,6 +68,39 @@ class UnitTests(unittest.TestCase):
 
         self.assertTrue(isinstance(str(mail), str))
 
+    def test_helloEmailAdditionalContent(self):
+        """Tests bug found in Issue-451 with Content ordering causing a crash"""
+
+        self.maxDiff = None
+
+        """Minimum required to send an email"""
+        mail = Mail()
+
+        mail.from_email = Email("test@example.com")
+
+        mail.subject = "Hello World from the SendGrid Python Library"
+
+        personalization = Personalization()
+        personalization.add_to(Email("test@example.com"))
+        mail.add_personalization(personalization)
+        
+        mail.add_content(Content("text/html", "<html><body>some text here</body></html>"))
+        mail.add_content(Content("text/plain", "some text here"))
+
+        self.assertEqual(
+            json.dumps(
+                mail.get(),
+                sort_keys=True),
+            '{"content": [{"type": "text/plain", "value": "some text here"}, '
+            '{"type": "text/html", '
+            '"value": "<html><body>some text here</body></html>"}], '
+            '"from": {"email": "test@example.com"}, "personalizations": '
+            '[{"to": [{"email": "test@example.com"}]}], '
+            '"subject": "Hello World from the SendGrid Python Library"}'
+        )
+
+        self.assertTrue(isinstance(str(mail), str))
+
     def test_kitchenSink(self):
         self.maxDiff = None