We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
SES support does not parse Source or Message['from'] for email address
The `From` header on MIME Messages can be either `email@domain` or `Name <email@domain>`. For my tests, I have a `From` header of `=?utf-8?q?Name?= <email@domain.com>` which is a valid format style for production emails.

Furthermore, AWS SES allows for either a `Source` (which overrides any Message['From']) or a Message['From'] to be specified.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `moto/ses/responses.py`
Content:
```
1 from __future__ import unicode_literals
2 import base64
3 
4 import six
5 
6 from moto.core.responses import BaseResponse
7 from .models import ses_backend
8 
9 
10 class EmailResponse(BaseResponse):
11 
12     def verify_email_identity(self):
13         address = self.querystring.get('EmailAddress')[0]
14         ses_backend.verify_email_identity(address)
15         template = self.response_template(VERIFY_EMAIL_IDENTITY)
16         return template.render()
17 
18     def verify_email_address(self):
19         address = self.querystring.get('EmailAddress')[0]
20         ses_backend.verify_email_address(address)
21         template = self.response_template(VERIFY_EMAIL_ADDRESS)
22         return template.render()
23 
24     def list_identities(self):
25         identities = ses_backend.list_identities()
26         template = self.response_template(LIST_IDENTITIES_RESPONSE)
27         return template.render(identities=identities)
28 
29     def list_verified_email_addresses(self):
30         email_addresses = ses_backend.list_verified_email_addresses()
31         template = self.response_template(LIST_VERIFIED_EMAIL_RESPONSE)
32         return template.render(email_addresses=email_addresses)
33 
34     def verify_domain_dkim(self):
35         domain = self.querystring.get('Domain')[0]
36         ses_backend.verify_domain(domain)
37         template = self.response_template(VERIFY_DOMAIN_DKIM_RESPONSE)
38         return template.render()
39 
40     def verify_domain_identity(self):
41         domain = self.querystring.get('Domain')[0]
42         ses_backend.verify_domain(domain)
43         template = self.response_template(VERIFY_DOMAIN_IDENTITY_RESPONSE)
44         return template.render()
45 
46     def delete_identity(self):
47         domain = self.querystring.get('Identity')[0]
48         ses_backend.delete_identity(domain)
49         template = self.response_template(DELETE_IDENTITY_RESPONSE)
50         return template.render()
51 
52     def send_email(self):
53         bodydatakey = 'Message.Body.Text.Data'
54         if 'Message.Body.Html.Data' in self.querystring:
55             bodydatakey = 'Message.Body.Html.Data'
56         body = self.querystring.get(bodydatakey)[0]
57         source = self.querystring.get('Source')[0]
58         subject = self.querystring.get('Message.Subject.Data')[0]
59         destinations = {
60             'ToAddresses': [],
61             'CcAddresses': [],
62             'BccAddresses': [],
63         }
64         for dest_type in destinations:
65             # consume up to 51 to allow exception
66             for i in six.moves.range(1, 52):
67                 field = 'Destination.%s.member.%s' % (dest_type, i)
68                 address = self.querystring.get(field)
69                 if address is None:
70                     break
71                 destinations[dest_type].append(address[0])
72 
73         message = ses_backend.send_email(source, subject, body, destinations)
74         template = self.response_template(SEND_EMAIL_RESPONSE)
75         return template.render(message=message)
76 
77     def send_raw_email(self):
78         source = self.querystring.get('Source')[0]
79         raw_data = self.querystring.get('RawMessage.Data')[0]
80         raw_data = base64.b64decode(raw_data)
81         if six.PY3:
82             raw_data = raw_data.decode('utf-8')
83         destinations = []
84         # consume up to 51 to allow exception
85         for i in six.moves.range(1, 52):
86             field = 'Destinations.member.%s' % i
87             address = self.querystring.get(field)
88             if address is None:
89                 break
90             destinations.append(address[0])
91 
92         message = ses_backend.send_raw_email(source, destinations, raw_data)
93         template = self.response_template(SEND_RAW_EMAIL_RESPONSE)
94         return template.render(message=message)
95 
96     def get_send_quota(self):
97         quota = ses_backend.get_send_quota()
98         template = self.response_template(GET_SEND_QUOTA_RESPONSE)
99         return template.render(quota=quota)
100 
101 
102 VERIFY_EMAIL_IDENTITY = """<VerifyEmailIdentityResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
103   <VerifyEmailIdentityResult/>
104   <ResponseMetadata>
105     <RequestId>47e0ef1a-9bf2-11e1-9279-0100e8cf109a</RequestId>
106   </ResponseMetadata>
107 </VerifyEmailIdentityResponse>"""
108 
109 VERIFY_EMAIL_ADDRESS = """<VerifyEmailAddressResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
110   <VerifyEmailAddressResult/>
111   <ResponseMetadata>
112     <RequestId>47e0ef1a-9bf2-11e1-9279-0100e8cf109a</RequestId>
113   </ResponseMetadata>
114 </VerifyEmailAddressResponse>"""
115 
116 LIST_IDENTITIES_RESPONSE = """<ListIdentitiesResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
117   <ListIdentitiesResult>
118     <Identities>
119         {% for identity in identities %}
120           <member>{{ identity }}</member>
121         {% endfor %}
122     </Identities>
123   </ListIdentitiesResult>
124   <ResponseMetadata>
125     <RequestId>cacecf23-9bf1-11e1-9279-0100e8cf109a</RequestId>
126   </ResponseMetadata>
127 </ListIdentitiesResponse>"""
128 
129 LIST_VERIFIED_EMAIL_RESPONSE = """<ListVerifiedEmailAddressesResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
130   <ListVerifiedEmailAddressesResult>
131     <VerifiedEmailAddresses>
132         {% for email in email_addresses %}
133           <member>{{ email }}</member>
134         {% endfor %}
135     </VerifiedEmailAddresses>
136   </ListVerifiedEmailAddressesResult>
137   <ResponseMetadata>
138     <RequestId>cacecf23-9bf1-11e1-9279-0100e8cf109a</RequestId>
139   </ResponseMetadata>
140 </ListVerifiedEmailAddressesResponse>"""
141 
142 VERIFY_DOMAIN_DKIM_RESPONSE = """<VerifyDomainDkimResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
143   <VerifyDomainDkimResult>
144     <DkimTokens>
145       <member>vvjuipp74whm76gqoni7qmwwn4w4qusjiainivf6sf</member>
146       <member>3frqe7jn4obpuxjpwpolz6ipb3k5nvt2nhjpik2oy</member>
147       <member>wrqplteh7oodxnad7hsl4mixg2uavzneazxv5sxi2</member>
148     </DkimTokens>
149     </VerifyDomainDkimResult>
150     <ResponseMetadata>
151       <RequestId>9662c15b-c469-11e1-99d1-797d6ecd6414</RequestId>
152     </ResponseMetadata>
153 </VerifyDomainDkimResponse>"""
154 
155 VERIFY_DOMAIN_IDENTITY_RESPONSE = """\
156 <VerifyDomainIdentityResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
157   <VerifyDomainIdentityResult>
158     <VerificationToken>QTKknzFg2J4ygwa+XvHAxUl1hyHoY0gVfZdfjIedHZ0=</VerificationToken>
159   </VerifyDomainIdentityResult>
160   <ResponseMetadata>
161     <RequestId>94f6368e-9bf2-11e1-8ee7-c98a0037a2b6</RequestId>
162   </ResponseMetadata>
163 </VerifyDomainIdentityResponse>"""
164 
165 DELETE_IDENTITY_RESPONSE = """<DeleteIdentityResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
166   <DeleteIdentityResult/>
167   <ResponseMetadata>
168     <RequestId>d96bd874-9bf2-11e1-8ee7-c98a0037a2b6</RequestId>
169   </ResponseMetadata>
170 </DeleteIdentityResponse>"""
171 
172 SEND_EMAIL_RESPONSE = """<SendEmailResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
173   <SendEmailResult>
174     <MessageId>{{ message.id }}</MessageId>
175   </SendEmailResult>
176   <ResponseMetadata>
177     <RequestId>d5964849-c866-11e0-9beb-01a62d68c57f</RequestId>
178   </ResponseMetadata>
179 </SendEmailResponse>"""
180 
181 SEND_RAW_EMAIL_RESPONSE = """<SendRawEmailResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
182   <SendRawEmailResult>
183     <MessageId>{{ message.id }}</MessageId>
184   </SendRawEmailResult>
185   <ResponseMetadata>
186     <RequestId>e0abcdfa-c866-11e0-b6d0-273d09173b49</RequestId>
187   </ResponseMetadata>
188 </SendRawEmailResponse>"""
189 
190 GET_SEND_QUOTA_RESPONSE = """<GetSendQuotaResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
191   <GetSendQuotaResult>
192     <SentLast24Hours>{{ quota.sent_past_24 }}</SentLast24Hours>
193     <Max24HourSend>200.0</Max24HourSend>
194     <MaxSendRate>1.0</MaxSendRate>
195   </GetSendQuotaResult>
196   <ResponseMetadata>
197     <RequestId>273021c6-c866-11e0-b926-699e21c3af9e</RequestId>
198   </ResponseMetadata>
199 </GetSendQuotaResponse>"""
200
```

Path: `moto/ses/models.py`
Content:
```
1 from __future__ import unicode_literals
2 
3 import email
4 
5 from moto.core import BaseBackend, BaseModel
6 from .exceptions import MessageRejectedError
7 from .utils import get_random_message_id
8 
9 
10 RECIPIENT_LIMIT = 50
11 
12 
13 class Message(BaseModel):
14 
15     def __init__(self, message_id):
16         self.id = message_id
17 
18 
19 class RawMessage(BaseModel):
20 
21     def __init__(self, message_id):
22         self.id = message_id
23 
24 
25 class SESQuota(BaseModel):
26 
27     def __init__(self, sent):
28         self.sent = sent
29 
30     @property
31     def sent_past_24(self):
32         return self.sent
33 
34 
35 class SESBackend(BaseBackend):
36 
37     def __init__(self):
38         self.addresses = []
39         self.email_addresses = []
40         self.domains = []
41         self.sent_messages = []
42         self.sent_message_count = 0
43 
44     def _is_verified_address(self, address):
45         if address in self.addresses:
46             return True
47         user, host = address.split('@', 1)
48         return host in self.domains
49 
50     def verify_email_identity(self, address):
51         self.addresses.append(address)
52 
53     def verify_email_address(self, address):
54         self.email_addresses.append(address)
55 
56     def verify_domain(self, domain):
57         self.domains.append(domain)
58 
59     def list_identities(self):
60         return self.domains + self.addresses
61 
62     def list_verified_email_addresses(self):
63         return self.email_addresses
64 
65     def delete_identity(self, identity):
66         if '@' in identity:
67             self.addresses.remove(identity)
68         else:
69             self.domains.remove(identity)
70 
71     def send_email(self, source, subject, body, destinations):
72         recipient_count = sum(map(len, destinations.values()))
73         if recipient_count > RECIPIENT_LIMIT:
74             raise MessageRejectedError('Too many recipients.')
75         if not self._is_verified_address(source):
76             raise MessageRejectedError(
77                 "Email address not verified %s" % source
78             )
79 
80         message_id = get_random_message_id()
81         message = Message(message_id)
82         self.sent_messages.append(message)
83         self.sent_message_count += recipient_count
84         return message
85 
86     def send_raw_email(self, source, destinations, raw_data):
87         if source not in self.addresses:
88             raise MessageRejectedError(
89                 "Did not have authority to send from email %s" % source
90             )
91 
92         recipient_count = len(destinations)
93         message = email.message_from_string(raw_data)
94         for header in 'TO', 'CC', 'BCC':
95             recipient_count += sum(
96                 d.strip() and 1 or 0
97                 for d in message.get(header, '').split(',')
98             )
99         if recipient_count > RECIPIENT_LIMIT:
100             raise MessageRejectedError('Too many recipients.')
101 
102         self.sent_message_count += recipient_count
103         message_id = get_random_message_id()
104         message = RawMessage(message_id)
105         self.sent_messages.append(message)
106         return message
107 
108     def get_send_quota(self):
109         return SESQuota(self.sent_message_count)
110 
111 
112 ses_backend = SESBackend()
113
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/moto/ses/models.py b/moto/ses/models.py
--- a/moto/ses/models.py
+++ b/moto/ses/models.py
@@ -1,6 +1,7 @@
 from __future__ import unicode_literals
 
 import email
+from email.utils import parseaddr
 
 from moto.core import BaseBackend, BaseModel
 from .exceptions import MessageRejectedError
@@ -84,13 +85,27 @@
         return message
 
     def send_raw_email(self, source, destinations, raw_data):
-        if source not in self.addresses:
-            raise MessageRejectedError(
-                "Did not have authority to send from email %s" % source
-            )
+        if source is not None:
+            _, source_email_address = parseaddr(source)
+            if source_email_address not in self.addresses:
+                raise MessageRejectedError(
+                    "Did not have authority to send from email %s" % source_email_address
+                )
 
         recipient_count = len(destinations)
         message = email.message_from_string(raw_data)
+        if source is None:
+            if message['from'] is None:
+                raise MessageRejectedError(
+                    "Source not specified"
+                )
+
+            _, source_email_address = parseaddr(message['from'])
+            if source_email_address not in self.addresses:
+                raise MessageRejectedError(
+                    "Did not have authority to send from email %s" % source_email_address
+                )
+
         for header in 'TO', 'CC', 'BCC':
             recipient_count += sum(
                 d.strip() and 1 or 0
diff --git a/moto/ses/responses.py b/moto/ses/responses.py
--- a/moto/ses/responses.py
+++ b/moto/ses/responses.py
@@ -75,7 +75,10 @@
         return template.render(message=message)
 
     def send_raw_email(self):
-        source = self.querystring.get('Source')[0]
+        source = self.querystring.get('Source')
+        if source is not None:
+            source, = source
+
         raw_data = self.querystring.get('RawMessage.Data')[0]
         raw_data = base64.b64decode(raw_data)
         if six.PY3:

{"golden_diff": "diff --git a/moto/ses/models.py b/moto/ses/models.py\n--- a/moto/ses/models.py\n+++ b/moto/ses/models.py\n@@ -1,6 +1,7 @@\n from __future__ import unicode_literals\n \n import email\n+from email.utils import parseaddr\n \n from moto.core import BaseBackend, BaseModel\n from .exceptions import MessageRejectedError\n@@ -84,13 +85,27 @@\n         return message\n \n     def send_raw_email(self, source, destinations, raw_data):\n-        if source not in self.addresses:\n-            raise MessageRejectedError(\n-                \"Did not have authority to send from email %s\" % source\n-            )\n+        if source is not None:\n+            _, source_email_address = parseaddr(source)\n+            if source_email_address not in self.addresses:\n+                raise MessageRejectedError(\n+                    \"Did not have authority to send from email %s\" % source_email_address\n+                )\n \n         recipient_count = len(destinations)\n         message = email.message_from_string(raw_data)\n+        if source is None:\n+            if message['from'] is None:\n+                raise MessageRejectedError(\n+                    \"Source not specified\"\n+                )\n+\n+            _, source_email_address = parseaddr(message['from'])\n+            if source_email_address not in self.addresses:\n+                raise MessageRejectedError(\n+                    \"Did not have authority to send from email %s\" % source_email_address\n+                )\n+\n         for header in 'TO', 'CC', 'BCC':\n             recipient_count += sum(\n                 d.strip() and 1 or 0\ndiff --git a/moto/ses/responses.py b/moto/ses/responses.py\n--- a/moto/ses/responses.py\n+++ b/moto/ses/responses.py\n@@ -75,7 +75,10 @@\n         return template.render(message=message)\n \n     def send_raw_email(self):\n-        source = self.querystring.get('Source')[0]\n+        source = self.querystring.get('Source')\n+        if source is not None:\n+            source, = source\n+\n         raw_data = self.querystring.get('RawMessage.Data')[0]\n         raw_data = base64.b64decode(raw_data)\n         if six.PY3:\n", "issue": "SES support does not parse Source or Message['from'] for email address\nThe `From` header on MIME Messages can be either `email@domain` or `Name <email@domain>`. For my tests, I have a `From` header of `=?utf-8?q?Name?= <email@domain.com>` which is a valid format style for production emails.\r\n\r\nFurthermore, AWS SES allows for either a `Source` (which overrides any Message['From']) or a Message['From'] to be specified.\n", "before_files": [{"content": "from __future__ import unicode_literals\nimport base64\n\nimport six\n\nfrom moto.core.responses import BaseResponse\nfrom .models import ses_backend\n\n\nclass EmailResponse(BaseResponse):\n\n    def verify_email_identity(self):\n        address = self.querystring.get('EmailAddress')[0]\n        ses_backend.verify_email_identity(address)\n        template = self.response_template(VERIFY_EMAIL_IDENTITY)\n        return template.render()\n\n    def verify_email_address(self):\n        address = self.querystring.get('EmailAddress')[0]\n        ses_backend.verify_email_address(address)\n        template = self.response_template(VERIFY_EMAIL_ADDRESS)\n        return template.render()\n\n    def list_identities(self):\n        identities = ses_backend.list_identities()\n        template = self.response_template(LIST_IDENTITIES_RESPONSE)\n        return template.render(identities=identities)\n\n    def list_verified_email_addresses(self):\n        email_addresses = ses_backend.list_verified_email_addresses()\n        template = self.response_template(LIST_VERIFIED_EMAIL_RESPONSE)\n        return template.render(email_addresses=email_addresses)\n\n    def verify_domain_dkim(self):\n        domain = self.querystring.get('Domain')[0]\n        ses_backend.verify_domain(domain)\n        template = self.response_template(VERIFY_DOMAIN_DKIM_RESPONSE)\n        return template.render()\n\n    def verify_domain_identity(self):\n        domain = self.querystring.get('Domain')[0]\n        ses_backend.verify_domain(domain)\n        template = self.response_template(VERIFY_DOMAIN_IDENTITY_RESPONSE)\n        return template.render()\n\n    def delete_identity(self):\n        domain = self.querystring.get('Identity')[0]\n        ses_backend.delete_identity(domain)\n        template = self.response_template(DELETE_IDENTITY_RESPONSE)\n        return template.render()\n\n    def send_email(self):\n        bodydatakey = 'Message.Body.Text.Data'\n        if 'Message.Body.Html.Data' in self.querystring:\n            bodydatakey = 'Message.Body.Html.Data'\n        body = self.querystring.get(bodydatakey)[0]\n        source = self.querystring.get('Source')[0]\n        subject = self.querystring.get('Message.Subject.Data')[0]\n        destinations = {\n            'ToAddresses': [],\n            'CcAddresses': [],\n            'BccAddresses': [],\n        }\n        for dest_type in destinations:\n            # consume up to 51 to allow exception\n            for i in six.moves.range(1, 52):\n                field = 'Destination.%s.member.%s' % (dest_type, i)\n                address = self.querystring.get(field)\n                if address is None:\n                    break\n                destinations[dest_type].append(address[0])\n\n        message = ses_backend.send_email(source, subject, body, destinations)\n        template = self.response_template(SEND_EMAIL_RESPONSE)\n        return template.render(message=message)\n\n    def send_raw_email(self):\n        source = self.querystring.get('Source')[0]\n        raw_data = self.querystring.get('RawMessage.Data')[0]\n        raw_data = base64.b64decode(raw_data)\n        if six.PY3:\n            raw_data = raw_data.decode('utf-8')\n        destinations = []\n        # consume up to 51 to allow exception\n        for i in six.moves.range(1, 52):\n            field = 'Destinations.member.%s' % i\n            address = self.querystring.get(field)\n            if address is None:\n                break\n            destinations.append(address[0])\n\n        message = ses_backend.send_raw_email(source, destinations, raw_data)\n        template = self.response_template(SEND_RAW_EMAIL_RESPONSE)\n        return template.render(message=message)\n\n    def get_send_quota(self):\n        quota = ses_backend.get_send_quota()\n        template = self.response_template(GET_SEND_QUOTA_RESPONSE)\n        return template.render(quota=quota)\n\n\nVERIFY_EMAIL_IDENTITY = \"\"\"<VerifyEmailIdentityResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <VerifyEmailIdentityResult/>\n  <ResponseMetadata>\n    <RequestId>47e0ef1a-9bf2-11e1-9279-0100e8cf109a</RequestId>\n  </ResponseMetadata>\n</VerifyEmailIdentityResponse>\"\"\"\n\nVERIFY_EMAIL_ADDRESS = \"\"\"<VerifyEmailAddressResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <VerifyEmailAddressResult/>\n  <ResponseMetadata>\n    <RequestId>47e0ef1a-9bf2-11e1-9279-0100e8cf109a</RequestId>\n  </ResponseMetadata>\n</VerifyEmailAddressResponse>\"\"\"\n\nLIST_IDENTITIES_RESPONSE = \"\"\"<ListIdentitiesResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <ListIdentitiesResult>\n    <Identities>\n        {% for identity in identities %}\n          <member>{{ identity }}</member>\n        {% endfor %}\n    </Identities>\n  </ListIdentitiesResult>\n  <ResponseMetadata>\n    <RequestId>cacecf23-9bf1-11e1-9279-0100e8cf109a</RequestId>\n  </ResponseMetadata>\n</ListIdentitiesResponse>\"\"\"\n\nLIST_VERIFIED_EMAIL_RESPONSE = \"\"\"<ListVerifiedEmailAddressesResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <ListVerifiedEmailAddressesResult>\n    <VerifiedEmailAddresses>\n        {% for email in email_addresses %}\n          <member>{{ email }}</member>\n        {% endfor %}\n    </VerifiedEmailAddresses>\n  </ListVerifiedEmailAddressesResult>\n  <ResponseMetadata>\n    <RequestId>cacecf23-9bf1-11e1-9279-0100e8cf109a</RequestId>\n  </ResponseMetadata>\n</ListVerifiedEmailAddressesResponse>\"\"\"\n\nVERIFY_DOMAIN_DKIM_RESPONSE = \"\"\"<VerifyDomainDkimResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <VerifyDomainDkimResult>\n    <DkimTokens>\n      <member>vvjuipp74whm76gqoni7qmwwn4w4qusjiainivf6sf</member>\n      <member>3frqe7jn4obpuxjpwpolz6ipb3k5nvt2nhjpik2oy</member>\n      <member>wrqplteh7oodxnad7hsl4mixg2uavzneazxv5sxi2</member>\n    </DkimTokens>\n    </VerifyDomainDkimResult>\n    <ResponseMetadata>\n      <RequestId>9662c15b-c469-11e1-99d1-797d6ecd6414</RequestId>\n    </ResponseMetadata>\n</VerifyDomainDkimResponse>\"\"\"\n\nVERIFY_DOMAIN_IDENTITY_RESPONSE = \"\"\"\\\n<VerifyDomainIdentityResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <VerifyDomainIdentityResult>\n    <VerificationToken>QTKknzFg2J4ygwa+XvHAxUl1hyHoY0gVfZdfjIedHZ0=</VerificationToken>\n  </VerifyDomainIdentityResult>\n  <ResponseMetadata>\n    <RequestId>94f6368e-9bf2-11e1-8ee7-c98a0037a2b6</RequestId>\n  </ResponseMetadata>\n</VerifyDomainIdentityResponse>\"\"\"\n\nDELETE_IDENTITY_RESPONSE = \"\"\"<DeleteIdentityResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <DeleteIdentityResult/>\n  <ResponseMetadata>\n    <RequestId>d96bd874-9bf2-11e1-8ee7-c98a0037a2b6</RequestId>\n  </ResponseMetadata>\n</DeleteIdentityResponse>\"\"\"\n\nSEND_EMAIL_RESPONSE = \"\"\"<SendEmailResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <SendEmailResult>\n    <MessageId>{{ message.id }}</MessageId>\n  </SendEmailResult>\n  <ResponseMetadata>\n    <RequestId>d5964849-c866-11e0-9beb-01a62d68c57f</RequestId>\n  </ResponseMetadata>\n</SendEmailResponse>\"\"\"\n\nSEND_RAW_EMAIL_RESPONSE = \"\"\"<SendRawEmailResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <SendRawEmailResult>\n    <MessageId>{{ message.id }}</MessageId>\n  </SendRawEmailResult>\n  <ResponseMetadata>\n    <RequestId>e0abcdfa-c866-11e0-b6d0-273d09173b49</RequestId>\n  </ResponseMetadata>\n</SendRawEmailResponse>\"\"\"\n\nGET_SEND_QUOTA_RESPONSE = \"\"\"<GetSendQuotaResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <GetSendQuotaResult>\n    <SentLast24Hours>{{ quota.sent_past_24 }}</SentLast24Hours>\n    <Max24HourSend>200.0</Max24HourSend>\n    <MaxSendRate>1.0</MaxSendRate>\n  </GetSendQuotaResult>\n  <ResponseMetadata>\n    <RequestId>273021c6-c866-11e0-b926-699e21c3af9e</RequestId>\n  </ResponseMetadata>\n</GetSendQuotaResponse>\"\"\"\n", "path": "moto/ses/responses.py"}, {"content": "from __future__ import unicode_literals\n\nimport email\n\nfrom moto.core import BaseBackend, BaseModel\nfrom .exceptions import MessageRejectedError\nfrom .utils import get_random_message_id\n\n\nRECIPIENT_LIMIT = 50\n\n\nclass Message(BaseModel):\n\n    def __init__(self, message_id):\n        self.id = message_id\n\n\nclass RawMessage(BaseModel):\n\n    def __init__(self, message_id):\n        self.id = message_id\n\n\nclass SESQuota(BaseModel):\n\n    def __init__(self, sent):\n        self.sent = sent\n\n    @property\n    def sent_past_24(self):\n        return self.sent\n\n\nclass SESBackend(BaseBackend):\n\n    def __init__(self):\n        self.addresses = []\n        self.email_addresses = []\n        self.domains = []\n        self.sent_messages = []\n        self.sent_message_count = 0\n\n    def _is_verified_address(self, address):\n        if address in self.addresses:\n            return True\n        user, host = address.split('@', 1)\n        return host in self.domains\n\n    def verify_email_identity(self, address):\n        self.addresses.append(address)\n\n    def verify_email_address(self, address):\n        self.email_addresses.append(address)\n\n    def verify_domain(self, domain):\n        self.domains.append(domain)\n\n    def list_identities(self):\n        return self.domains + self.addresses\n\n    def list_verified_email_addresses(self):\n        return self.email_addresses\n\n    def delete_identity(self, identity):\n        if '@' in identity:\n            self.addresses.remove(identity)\n        else:\n            self.domains.remove(identity)\n\n    def send_email(self, source, subject, body, destinations):\n        recipient_count = sum(map(len, destinations.values()))\n        if recipient_count > RECIPIENT_LIMIT:\n            raise MessageRejectedError('Too many recipients.')\n        if not self._is_verified_address(source):\n            raise MessageRejectedError(\n                \"Email address not verified %s\" % source\n            )\n\n        message_id = get_random_message_id()\n        message = Message(message_id)\n        self.sent_messages.append(message)\n        self.sent_message_count += recipient_count\n        return message\n\n    def send_raw_email(self, source, destinations, raw_data):\n        if source not in self.addresses:\n            raise MessageRejectedError(\n                \"Did not have authority to send from email %s\" % source\n            )\n\n        recipient_count = len(destinations)\n        message = email.message_from_string(raw_data)\n        for header in 'TO', 'CC', 'BCC':\n            recipient_count += sum(\n                d.strip() and 1 or 0\n                for d in message.get(header, '').split(',')\n            )\n        if recipient_count > RECIPIENT_LIMIT:\n            raise MessageRejectedError('Too many recipients.')\n\n        self.sent_message_count += recipient_count\n        message_id = get_random_message_id()\n        message = RawMessage(message_id)\n        self.sent_messages.append(message)\n        return message\n\n    def get_send_quota(self):\n        return SESQuota(self.sent_message_count)\n\n\nses_backend = SESBackend()\n", "path": "moto/ses/models.py"}], "after_files": [{"content": "from __future__ import unicode_literals\nimport base64\n\nimport six\n\nfrom moto.core.responses import BaseResponse\nfrom .models import ses_backend\n\n\nclass EmailResponse(BaseResponse):\n\n    def verify_email_identity(self):\n        address = self.querystring.get('EmailAddress')[0]\n        ses_backend.verify_email_identity(address)\n        template = self.response_template(VERIFY_EMAIL_IDENTITY)\n        return template.render()\n\n    def verify_email_address(self):\n        address = self.querystring.get('EmailAddress')[0]\n        ses_backend.verify_email_address(address)\n        template = self.response_template(VERIFY_EMAIL_ADDRESS)\n        return template.render()\n\n    def list_identities(self):\n        identities = ses_backend.list_identities()\n        template = self.response_template(LIST_IDENTITIES_RESPONSE)\n        return template.render(identities=identities)\n\n    def list_verified_email_addresses(self):\n        email_addresses = ses_backend.list_verified_email_addresses()\n        template = self.response_template(LIST_VERIFIED_EMAIL_RESPONSE)\n        return template.render(email_addresses=email_addresses)\n\n    def verify_domain_dkim(self):\n        domain = self.querystring.get('Domain')[0]\n        ses_backend.verify_domain(domain)\n        template = self.response_template(VERIFY_DOMAIN_DKIM_RESPONSE)\n        return template.render()\n\n    def verify_domain_identity(self):\n        domain = self.querystring.get('Domain')[0]\n        ses_backend.verify_domain(domain)\n        template = self.response_template(VERIFY_DOMAIN_IDENTITY_RESPONSE)\n        return template.render()\n\n    def delete_identity(self):\n        domain = self.querystring.get('Identity')[0]\n        ses_backend.delete_identity(domain)\n        template = self.response_template(DELETE_IDENTITY_RESPONSE)\n        return template.render()\n\n    def send_email(self):\n        bodydatakey = 'Message.Body.Text.Data'\n        if 'Message.Body.Html.Data' in self.querystring:\n            bodydatakey = 'Message.Body.Html.Data'\n        body = self.querystring.get(bodydatakey)[0]\n        source = self.querystring.get('Source')[0]\n        subject = self.querystring.get('Message.Subject.Data')[0]\n        destinations = {\n            'ToAddresses': [],\n            'CcAddresses': [],\n            'BccAddresses': [],\n        }\n        for dest_type in destinations:\n            # consume up to 51 to allow exception\n            for i in six.moves.range(1, 52):\n                field = 'Destination.%s.member.%s' % (dest_type, i)\n                address = self.querystring.get(field)\n                if address is None:\n                    break\n                destinations[dest_type].append(address[0])\n\n        message = ses_backend.send_email(source, subject, body, destinations)\n        template = self.response_template(SEND_EMAIL_RESPONSE)\n        return template.render(message=message)\n\n    def send_raw_email(self):\n        source = self.querystring.get('Source')\n        if source is not None:\n            source, = source\n\n        raw_data = self.querystring.get('RawMessage.Data')[0]\n        raw_data = base64.b64decode(raw_data)\n        if six.PY3:\n            raw_data = raw_data.decode('utf-8')\n        destinations = []\n        # consume up to 51 to allow exception\n        for i in six.moves.range(1, 52):\n            field = 'Destinations.member.%s' % i\n            address = self.querystring.get(field)\n            if address is None:\n                break\n            destinations.append(address[0])\n\n        message = ses_backend.send_raw_email(source, destinations, raw_data)\n        template = self.response_template(SEND_RAW_EMAIL_RESPONSE)\n        return template.render(message=message)\n\n    def get_send_quota(self):\n        quota = ses_backend.get_send_quota()\n        template = self.response_template(GET_SEND_QUOTA_RESPONSE)\n        return template.render(quota=quota)\n\n\nVERIFY_EMAIL_IDENTITY = \"\"\"<VerifyEmailIdentityResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <VerifyEmailIdentityResult/>\n  <ResponseMetadata>\n    <RequestId>47e0ef1a-9bf2-11e1-9279-0100e8cf109a</RequestId>\n  </ResponseMetadata>\n</VerifyEmailIdentityResponse>\"\"\"\n\nVERIFY_EMAIL_ADDRESS = \"\"\"<VerifyEmailAddressResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <VerifyEmailAddressResult/>\n  <ResponseMetadata>\n    <RequestId>47e0ef1a-9bf2-11e1-9279-0100e8cf109a</RequestId>\n  </ResponseMetadata>\n</VerifyEmailAddressResponse>\"\"\"\n\nLIST_IDENTITIES_RESPONSE = \"\"\"<ListIdentitiesResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <ListIdentitiesResult>\n    <Identities>\n        {% for identity in identities %}\n          <member>{{ identity }}</member>\n        {% endfor %}\n    </Identities>\n  </ListIdentitiesResult>\n  <ResponseMetadata>\n    <RequestId>cacecf23-9bf1-11e1-9279-0100e8cf109a</RequestId>\n  </ResponseMetadata>\n</ListIdentitiesResponse>\"\"\"\n\nLIST_VERIFIED_EMAIL_RESPONSE = \"\"\"<ListVerifiedEmailAddressesResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <ListVerifiedEmailAddressesResult>\n    <VerifiedEmailAddresses>\n        {% for email in email_addresses %}\n          <member>{{ email }}</member>\n        {% endfor %}\n    </VerifiedEmailAddresses>\n  </ListVerifiedEmailAddressesResult>\n  <ResponseMetadata>\n    <RequestId>cacecf23-9bf1-11e1-9279-0100e8cf109a</RequestId>\n  </ResponseMetadata>\n</ListVerifiedEmailAddressesResponse>\"\"\"\n\nVERIFY_DOMAIN_DKIM_RESPONSE = \"\"\"<VerifyDomainDkimResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <VerifyDomainDkimResult>\n    <DkimTokens>\n      <member>vvjuipp74whm76gqoni7qmwwn4w4qusjiainivf6sf</member>\n      <member>3frqe7jn4obpuxjpwpolz6ipb3k5nvt2nhjpik2oy</member>\n      <member>wrqplteh7oodxnad7hsl4mixg2uavzneazxv5sxi2</member>\n    </DkimTokens>\n    </VerifyDomainDkimResult>\n    <ResponseMetadata>\n      <RequestId>9662c15b-c469-11e1-99d1-797d6ecd6414</RequestId>\n    </ResponseMetadata>\n</VerifyDomainDkimResponse>\"\"\"\n\nVERIFY_DOMAIN_IDENTITY_RESPONSE = \"\"\"\\\n<VerifyDomainIdentityResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <VerifyDomainIdentityResult>\n    <VerificationToken>QTKknzFg2J4ygwa+XvHAxUl1hyHoY0gVfZdfjIedHZ0=</VerificationToken>\n  </VerifyDomainIdentityResult>\n  <ResponseMetadata>\n    <RequestId>94f6368e-9bf2-11e1-8ee7-c98a0037a2b6</RequestId>\n  </ResponseMetadata>\n</VerifyDomainIdentityResponse>\"\"\"\n\nDELETE_IDENTITY_RESPONSE = \"\"\"<DeleteIdentityResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <DeleteIdentityResult/>\n  <ResponseMetadata>\n    <RequestId>d96bd874-9bf2-11e1-8ee7-c98a0037a2b6</RequestId>\n  </ResponseMetadata>\n</DeleteIdentityResponse>\"\"\"\n\nSEND_EMAIL_RESPONSE = \"\"\"<SendEmailResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <SendEmailResult>\n    <MessageId>{{ message.id }}</MessageId>\n  </SendEmailResult>\n  <ResponseMetadata>\n    <RequestId>d5964849-c866-11e0-9beb-01a62d68c57f</RequestId>\n  </ResponseMetadata>\n</SendEmailResponse>\"\"\"\n\nSEND_RAW_EMAIL_RESPONSE = \"\"\"<SendRawEmailResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <SendRawEmailResult>\n    <MessageId>{{ message.id }}</MessageId>\n  </SendRawEmailResult>\n  <ResponseMetadata>\n    <RequestId>e0abcdfa-c866-11e0-b6d0-273d09173b49</RequestId>\n  </ResponseMetadata>\n</SendRawEmailResponse>\"\"\"\n\nGET_SEND_QUOTA_RESPONSE = \"\"\"<GetSendQuotaResponse xmlns=\"http://ses.amazonaws.com/doc/2010-12-01/\">\n  <GetSendQuotaResult>\n    <SentLast24Hours>{{ quota.sent_past_24 }}</SentLast24Hours>\n    <Max24HourSend>200.0</Max24HourSend>\n    <MaxSendRate>1.0</MaxSendRate>\n  </GetSendQuotaResult>\n  <ResponseMetadata>\n    <RequestId>273021c6-c866-11e0-b926-699e21c3af9e</RequestId>\n  </ResponseMetadata>\n</GetSendQuotaResponse>\"\"\"\n", "path": "moto/ses/responses.py"}, {"content": "from __future__ import unicode_literals\n\nimport email\nfrom email.utils import parseaddr\n\nfrom moto.core import BaseBackend, BaseModel\nfrom .exceptions import MessageRejectedError\nfrom .utils import get_random_message_id\n\n\nRECIPIENT_LIMIT = 50\n\n\nclass Message(BaseModel):\n\n    def __init__(self, message_id):\n        self.id = message_id\n\n\nclass RawMessage(BaseModel):\n\n    def __init__(self, message_id):\n        self.id = message_id\n\n\nclass SESQuota(BaseModel):\n\n    def __init__(self, sent):\n        self.sent = sent\n\n    @property\n    def sent_past_24(self):\n        return self.sent\n\n\nclass SESBackend(BaseBackend):\n\n    def __init__(self):\n        self.addresses = []\n        self.email_addresses = []\n        self.domains = []\n        self.sent_messages = []\n        self.sent_message_count = 0\n\n    def _is_verified_address(self, address):\n        if address in self.addresses:\n            return True\n        user, host = address.split('@', 1)\n        return host in self.domains\n\n    def verify_email_identity(self, address):\n        self.addresses.append(address)\n\n    def verify_email_address(self, address):\n        self.email_addresses.append(address)\n\n    def verify_domain(self, domain):\n        self.domains.append(domain)\n\n    def list_identities(self):\n        return self.domains + self.addresses\n\n    def list_verified_email_addresses(self):\n        return self.email_addresses\n\n    def delete_identity(self, identity):\n        if '@' in identity:\n            self.addresses.remove(identity)\n        else:\n            self.domains.remove(identity)\n\n    def send_email(self, source, subject, body, destinations):\n        recipient_count = sum(map(len, destinations.values()))\n        if recipient_count > RECIPIENT_LIMIT:\n            raise MessageRejectedError('Too many recipients.')\n        if not self._is_verified_address(source):\n            raise MessageRejectedError(\n                \"Email address not verified %s\" % source\n            )\n\n        message_id = get_random_message_id()\n        message = Message(message_id)\n        self.sent_messages.append(message)\n        self.sent_message_count += recipient_count\n        return message\n\n    def send_raw_email(self, source, destinations, raw_data):\n        if source is not None:\n            _, source_email_address = parseaddr(source)\n            if source_email_address not in self.addresses:\n                raise MessageRejectedError(\n                    \"Did not have authority to send from email %s\" % source_email_address\n                )\n\n        recipient_count = len(destinations)\n        message = email.message_from_string(raw_data)\n        if source is None:\n            if message['from'] is None:\n                raise MessageRejectedError(\n                    \"Source not specified\"\n                )\n\n            _, source_email_address = parseaddr(message['from'])\n            if source_email_address not in self.addresses:\n                raise MessageRejectedError(\n                    \"Did not have authority to send from email %s\" % source_email_address\n                )\n\n        for header in 'TO', 'CC', 'BCC':\n            recipient_count += sum(\n                d.strip() and 1 or 0\n                for d in message.get(header, '').split(',')\n            )\n        if recipient_count > RECIPIENT_LIMIT:\n            raise MessageRejectedError('Too many recipients.')\n\n        self.sent_message_count += recipient_count\n        message_id = get_random_message_id()\n        message = RawMessage(message_id)\n        self.sent_messages.append(message)\n        return message\n\n    def get_send_quota(self):\n        return SESQuota(self.sent_message_count)\n\n\nses_backend = SESBackend()\n", "path": "moto/ses/models.py"}]}