Repository: sendgrid/sendgrid-python

Issue:
Feature request: Support for sending email.message.EmailMessage
I am working on integrating SendGrid into an application where I already have email messages as [email.message.EmailMessage](https://docs.python.org/3.6/library/email.message.html#email.message.EmailMessage), it would be really awesome if there was a way for me to send an `EmailMessage` directly rather than having to reconstruct .

Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/sendgrid/sendgrid-python/pull/631?src=pr&el=h1) Report
> Merging [#631](https://codecov.io/gh/sendgrid/sendgrid-python/pull/631?src=pr&el=desc) into [master](https://codecov.io/gh/sendgrid/sendgrid-python/commit/f132e5ba71391f2390d94fb8743e5cb2aed0beb9?src=pr&el=desc) will **increase** coverage by `0.09%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/sendgrid/sendgrid-python/pull/631/graphs/tree.svg?width=650&token=Yq0yTs1Nfq&height=150&src=pr)](https://codecov.io/gh/sendgrid/sendgrid-python/pull/631?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #631      +/-   ##
==========================================
+ Coverage   84.77%   84.86%   +0.09%     
==========================================
  Files          35       35              
  Lines        1156     1163       +7     
  Branches      172      173       +1     
==========================================
+ Hits          980      987       +7     
  Misses         90       90              
  Partials       86       86
```


| [Impacted Files](https://codecov.io/gh/sendgrid/sendgrid-python/pull/631?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [sendgrid/helpers/mail/mail.py](https://codecov.io/gh/sendgrid/sendgrid-python/pull/631/diff?src=pr&el=tree#diff-c2VuZGdyaWQvaGVscGVycy9tYWlsL21haWwucHk=) | `93.97% <100%> (+0.26%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/sendgrid/sendgrid-python/pull/631?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/sendgrid/sendgrid-python/pull/631?src=pr&el=footer). Last update [f132e5b...bb417a1](https://codecov.io/gh/sendgrid/sendgrid-python/pull/631?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/sendgrid/helpers/mail/mail.py b/sendgrid/helpers/mail/mail.py
index f374e6a..c27fc72 100644
--- a/sendgrid/helpers/mail/mail.py
+++ b/sendgrid/helpers/mail/mail.py
@@ -1,6 +1,8 @@
 """v3/mail/send response body builder"""
 from .personalization import Personalization
 from .header import Header
+from .email import Email
+from .content import Content
 
 
 class Mail(object):
@@ -141,3 +143,28 @@ class Mail(object):
 
         return {key: value for key, value in mail.items()
                 if value is not None and value != [] and value != {}}
+
+    @classmethod
+    def from_EmailMessage(cls, message):
+        """Create a Mail object from an instance of
+        email.message.EmailMessage.
+        :type message: email.message.EmailMessage
+        :rtype: Mail
+        """
+        mail = cls(
+            from_email=Email(message.get('From')),
+            subject=message.get('Subject'),
+            to_email=Email(message.get('To')),
+        )
+        try:
+            body = message.get_content()
+        except AttributeError:
+            # Python2
+            body = message.get_payload()
+        mail.add_content(Content(
+            message.get_content_type(),
+            body.strip()
+        ))
+        for k, v in message.items():
+            mail.add_header(Header(k, v))
+        return mail


Test patch:
diff --git a/test/test_mail.py b/test/test_mail.py
index 98af29a..8ebe3eb 100644
--- a/test/test_mail.py
+++ b/test/test_mail.py
@@ -2,6 +2,13 @@
 import json
 import unittest
 
+try:
+    from email.message import EmailMessage
+except ImportError:
+    # Python2
+    from email import message
+    EmailMessage = message.Message
+
 from sendgrid.helpers.mail import (
     ASM,
     APIKeyIncludedException,
@@ -557,3 +564,26 @@ class UnitTests(unittest.TestCase):
     def test_directly_setting_substitutions(self):
         personalization = Personalization()
         personalization.substitutions = [{'a': 0}]
+
+    def test_from_emailmessage(self):
+        message = EmailMessage()
+        body = 'message that is not urgent'
+        try:
+            message.set_content(body)
+        except AttributeError:
+            # Python2
+            message.set_payload(body)
+        message.set_default_type('text/plain')
+        message['Subject'] = 'URGENT TITLE'
+        message['From'] = 'test@example.com'
+        message['To'] = 'test@sendgrid.com'
+        mail = Mail.from_EmailMessage(message)
+        self.assertEqual(mail.subject, 'URGENT TITLE')
+        self.assertEqual(mail.from_email.email, 'test@example.com')
+        self.assertEqual(len(mail.personalizations), 1)
+        self.assertEqual(len(mail.personalizations[0].tos), 1)
+        self.assertEqual(mail.personalizations[0].tos[0], {'email': 'test@sendgrid.com'})
+        self.assertEqual(len(mail.contents), 1)
+        content = mail.contents[0]
+        self.assertEqual(content.type, 'text/plain')
+        self.assertEqual(content.value, 'message that is not urgent')