Skip to content

Commit ad51b4d

Browse files
Merge pull request #301 from GoogleCloudPlatform/mergeMail
Add mail samples.
2 parents 9a08ede + cac95a7 commit ad51b4d

18 files changed

+655
-0
lines changed

appengine/__init__.py

Whitespace-only changes.

appengine/mail/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## App Engine Email Docs Snippets
2+
3+
This sample application demonstrates different ways to send and receive email
4+
on App Engine
5+
6+
7+
<!-- auto-doc-link --><!-- end-auto-doc-link -->

appengine/mail/app.yaml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
runtime: python27
2+
api_version: 1
3+
threadsafe: yes
4+
5+
# [START bounce_service]
6+
# [START mail_service]
7+
inbound_services:
8+
- mail
9+
# [END mail_service]
10+
- mail_bounce
11+
# [END bounce_service]
12+
13+
handlers:
14+
- url: /user/.+
15+
script: user_signup.app
16+
- url: /send_mail
17+
script: send_mail.app
18+
- url: /send_message
19+
script: send_message.app
20+
# [START handle_incoming_email]
21+
- url: /_ah/mail/.+
22+
script: handle_incoming_email.app
23+
login: admin
24+
# [END handle_incoming_email]
25+
# [START handle_all_email]
26+
- url: /_ah/mail/owner@.*your_app_id\.appspotmail\.com
27+
script: handle_owner.app
28+
login: admin
29+
- url: /_ah/mail/support@.*your_app_id\.appspotmail\.com
30+
script: handle_support.app
31+
login: admin
32+
- url: /_ah/mail/.+
33+
script: handle_catchall.app
34+
login: admin
35+
# [END handle_all_email]
36+
# [START handle_bounced_email]
37+
- url: /_ah/bounce
38+
script: handle_bounced_email.app
39+
login: admin
40+
# [END handle_bounced_email]
41+
- url: /attachment
42+
script: attachment.app
43+
- url: /header
44+
script: header.app
45+
- url: /
46+
static_files: index.html
47+
upload: index.html

appengine/mail/attachment.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Copyright 2016 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from google.appengine.api import app_identity
16+
from google.appengine.api import mail
17+
import webapp2
18+
19+
20+
# [START send_attachment]
21+
class AttachmentHandler(webapp2.RequestHandler):
22+
def post(self):
23+
f = self.request.POST['file']
24+
mail.send_mail(sender='{}@appspot.gserviceaccount.com'.format(
25+
app_identity.get_application_id()),
26+
to="Albert Johnson <[email protected]>",
27+
subject="The doc you requested",
28+
body="""
29+
Attached is the document file you requested.
30+
31+
The example.com Team
32+
""",
33+
attachments=[(f.filename, f.file.read())])
34+
# [END send_attachment]
35+
self.response.content_type = 'text/plain'
36+
self.response.write('Sent {} to Albert.'.format(f.filename))
37+
38+
def get(self):
39+
self.response.content_type = 'text/html'
40+
self.response.write("""<html><body>
41+
<form method="post" enctype="multipart/form-data">
42+
Send a file to Albert:<br />
43+
<input type="file" name="file"><br /><br />
44+
<input type="submit" name="submit" value="Submit">
45+
</form></body></html""")
46+
47+
48+
app = webapp2.WSGIApplication([
49+
('/attachment', AttachmentHandler),
50+
], debug=True)

appengine/mail/attachment_test.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright 2016 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the 'License');
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an 'AS IS' BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import attachment
16+
import webtest
17+
18+
19+
def test_send_mail(testbed):
20+
testbed.init_mail_stub()
21+
testbed.init_app_identity_stub()
22+
app = webtest.TestApp(attachment.app)
23+
response = app.post('/attachment', upload_files=[
24+
('file', 'hello.txt', 'Good day!')])
25+
assert response.status_int == 200
26+
assert 'Sent hello.txt to Albert.' in response.body
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Copyright 2016 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import logging
16+
17+
from google.appengine.ext.webapp.mail_handlers import BounceNotificationHandler
18+
import webapp2
19+
20+
21+
# [START bounce_handler]
22+
class LogBounceHandler(BounceNotificationHandler):
23+
def receive(self, bounce_message):
24+
logging.info('Received bounce post ... [%s]', self.request)
25+
logging.info('Bounce original: %s', bounce_message.original)
26+
logging.info('Bounce notification: %s', bounce_message.notification)
27+
# [END bounce_handler]
28+
29+
app = webapp2.WSGIApplication([LogBounceHandler.mapping()], debug=True)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright 2016 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the 'License');
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an 'AS IS' BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from google.appengine.ext.webapp.mail_handlers import BounceNotification
16+
17+
import handle_bounced_email
18+
19+
20+
def test_handle_bounced_email(testbed):
21+
handler = handle_bounced_email.LogBounceHandler()
22+
handler.request = 'request'
23+
bounced_message = BounceNotification({})
24+
handler.receive(bounced_message)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Copyright 2016 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# [START log_sender_handler]
16+
import logging
17+
18+
from google.appengine.ext.webapp.mail_handlers import InboundMailHandler
19+
import webapp2
20+
21+
22+
class LogSenderHandler(InboundMailHandler):
23+
def receive(self, mail_message):
24+
logging.info("Received a message from: " + mail_message.sender)
25+
# [END log_sender_handler]
26+
# [START bodies]
27+
plaintext_bodies = mail_message.bodies('text/plain')
28+
html_bodies = mail_message.bodies('text/html')
29+
30+
for content_type, body in html_bodies:
31+
decoded_html = body.decode()
32+
# ...
33+
# [END bodies]
34+
logging.info("Html body of length %d.", len(decoded_html))
35+
for content_type, body in plaintext_bodies:
36+
plaintext = body.decode()
37+
logging.info("Plain text body of length %d.", len(plaintext))
38+
39+
# [START app]
40+
app = webapp2.WSGIApplication([LogSenderHandler.mapping()], debug=True)
41+
# [END app]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Copyright 2016 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the 'License');
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an 'AS IS' BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from google.appengine.api import mail
16+
17+
import handle_incoming_email
18+
19+
20+
def test_handle_bounced_email(testbed):
21+
handler = handle_incoming_email.LogSenderHandler()
22+
handler.request = 'request'
23+
message = mail.EmailMessage(
24+
25+
subject='Your account has been approved')
26+
message.to = 'Albert Johnson <[email protected]>'
27+
message.body = 'Dear Albert.'
28+
handler.receive(message)

appengine/mail/header.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Copyright 2016 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from google.appengine.api import app_identity
16+
from google.appengine.api import mail
17+
import webapp2
18+
19+
20+
def send_example_mail(sender_address, email_thread_id):
21+
# [BEGIN send_mail]
22+
mail.send_mail(sender=sender_address,
23+
to="Albert Johnson <[email protected]>",
24+
subject="An example email",
25+
body="""
26+
The email references a given email thread id.
27+
28+
The example.com Team
29+
""",
30+
headers={"References": email_thread_id})
31+
# [SEND send_mail]
32+
33+
34+
class SendMailHandler(webapp2.RequestHandler):
35+
def get(self):
36+
self.response.content_type = 'text/html'
37+
self.response.write("""<html><body><form method="POST">
38+
Enter an email thread id: <input name="thread_id">
39+
<input type=submit>
40+
</form></body></html>""")
41+
42+
def post(self):
43+
print repr(self.request.POST)
44+
id = self.request.POST['thread_id']
45+
send_example_mail('{}@appspot.gserviceaccount.com'.format(
46+
app_identity.get_application_id()), id)
47+
self.response.content_type = 'text/plain'
48+
self.response.write(
49+
'Sent an email to Albert with Reference header set to {}.'
50+
.format(id))
51+
52+
53+
app = webapp2.WSGIApplication([
54+
('/header', SendMailHandler),
55+
], debug=True)

appengine/mail/header_test.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright 2016 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the 'License');
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an 'AS IS' BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import header
16+
import webtest
17+
18+
19+
def test_send_mail(testbed):
20+
testbed.init_mail_stub()
21+
testbed.init_app_identity_stub()
22+
app = webtest.TestApp(header.app)
23+
response = app.post('/header', 'thread_id=42')
24+
assert response.status_int == 200
25+
assert ('Sent an email to Albert with Reference header set to 42.'
26+
in response.body)

appengine/mail/index.html

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE html>
2+
<!--
3+
Copyright 2016 Google Inc. All rights reserved.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
-->
17+
<html lang="en">
18+
<head>
19+
<meta charset="UTF-8">
20+
<title>Google App Engine Mail Samples</title>
21+
</head>
22+
<body>
23+
<p><a href="send_mail">Send email.</a></p>
24+
<p><a href="send_message">Send email with a message object.</a></p>
25+
<p><a href="user/signup">Confirm a user's email address.</a></p>
26+
<p><a href="attachment">Send email with attachments.</a></p>
27+
<p><a href="header">Send email with headers.</a></p>
28+
</body>
29+
</html>

0 commit comments

Comments
 (0)