Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support for AMP HTML Email #945

Merged
merged 14 commits into from
Jan 8, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions sendgrid/helpers/mail/amp_html_content.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from .content import Content
from .validators import ValidateApiKey


class AmpHtmlContent(Content):
"""AMP HTML content to be included in your email."""

def __init__(self, content):
"""Create an AMP HTML Content with the specified MIME type and content.

:param content: The AMP HTML content.
:type content: string
"""
self._content = None
self._validator = ValidateApiKey()

if content is not None:
self.content = content

@property
def mime_type(self):
"""The MIME type for AMP HTML content.

:rtype: string
"""
return "text/html"

@property
def content(self):
"""The actual AMP HTML content.

:rtype: string
"""
return self._content

@content.setter
def content(self, value):
"""The actual AMP HTML content.

:param value: The actual AMP HTML content.
:type value: string
"""
self._validator.validate_message_dict(value)
self._content = value

def get(self):
"""
Get a JSON-ready representation of this AmpContent.

:returns: This AmpContent, ready for use in a request body.
:rtype: dict
"""
content = {}
if self.mime_type is not None:
content["type"] = self.mime_type

if self.content is not None:
content["value"] = self.content
return content
6 changes: 3 additions & 3 deletions sendgrid/helpers/mail/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def __init__(self, mime_type, content):
@property
def mime_type(self):
"""The MIME type of the content you are including in your email.
For example, "text/plain" or "text/html".
For example, "text/plain" or "text/html" or "text/x-amp-html".

:rtype: string
"""
Expand All @@ -38,11 +38,11 @@ def mime_type(self):
@mime_type.setter
def mime_type(self, value):
"""The MIME type of the content you are including in your email.
For example, "text/plain" or "text/html".
For example, "text/plain" or "text/html" or "text/x-amp-html".

:param value: The MIME type of the content you are including in your
email.
For example, "text/plain" or "text/html".
For example, "text/plain" or "text/html" or "text/x-amp-html".
:type value: string
"""
self._mime_type = value
Expand Down
14 changes: 13 additions & 1 deletion sendgrid/helpers/mail/mail.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def __init__(
subject=None,
plain_text_content=None,
html_content=None,
amp_html_content=None,
global_substitutions=None,
is_multiple=False):
"""
Expand All @@ -43,6 +44,8 @@ def __init__(
:type plain_text_content: string, optional
:param html_content: The html body of the email
:type html_content: string, optional
:param amp_html_content: The amp-html body of the email
:type amp_html_content: string, optional
"""
self._attachments = None
self._categories = None
Expand Down Expand Up @@ -71,6 +74,8 @@ def __init__(
self.subject = subject
if plain_text_content is not None:
self.add_content(plain_text_content, MimeType.text)
if amp_html_content is not None:
self.add_content(amp_html_content, MimeType.amp)
if html_content is not None:
self.add_content(html_content, MimeType.html)

Expand Down Expand Up @@ -725,9 +730,16 @@ def add_content(self, content, mime_type=None):
"""
if isinstance(content, str):
content = Content(mime_type, content)
# Content of mime type text/plain must always come first
# Content of mime type text/plain must always come first, followed by text/x-amp-html and then text/html
modernwarfareuplink marked this conversation as resolved.
Show resolved Hide resolved
if content.mime_type == "text/plain":
self._contents = self._ensure_insert(content, self._contents)
elif content.mime_type == "text/x-amp-html":
if self._contents:
index = len(self._contents)
else:
index = 0
self._contents = self._ensure_append(
content, self._contents, index=index)
else:
if self._contents:
index = len(self._contents)
Expand Down
1 change: 1 addition & 0 deletions sendgrid/helpers/mail/mime_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ class MimeType(object):
"""
text = "text/plain"
html = "text/html"
amp = "text/x-amp-html"
99 changes: 99 additions & 0 deletions use_cases/sending_amp_html_content.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Sending AMP-HTML Email


Currently, we require AMP HTML and any one of HTML or Plain Text content for improved deliverability or fallback for AMP HTML Email for supporting older clients and showing alternate content after 30 days. In some cases, only HTML may be available. The below example shows how to obtain the Plain Text equivalent of the HTML content.
modernwarfareuplink marked this conversation as resolved.
Show resolved Hide resolved

```python
import os
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail

# The below amp html email is taken from [Google AMP Hello World Email](https://amp.dev/documentation/examples/introduction/hello_world_email/)
amp_html_content = '''
<!--
## Introduction

Learn how to create your first AMP email. This sample covers the basic structure of AMP emails.
-->

<!-- -->
<!-- Doctype declaration is required. -->
<!doctype html>
<!-- This tells everyone that this is an AMP email. `<html amp4email>` works too. -->
<html ⚡4email>
<!-- ## Head -->
<!-- -->
<head>
<!-- The charset definition must be the first child of the `<head>` tag. -->
<meta charset="utf-8">
<!-- The AMP runtime.-->
<script async src="https://cdn.ampproject.org/v0.js"></script>
<!-- The AMP for Email boilerplate. -->
<style amp4email-boilerplate>body{visibility:hidden}</style>
<!-- Import AMP components in the header, for example the `amp-carousel` component. -->
<script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>
<!--
### Allowed CSS properties and selectors

All CSS in any AMP document must be included in a `<style amp-custom>` tag within the header as shown above. Inline style attributes are not allowed in AMP. CSS allowed within email messages vary depending on the email provider. For reference, the list of CSS properties and values allowed in Gmail can be found at [Gmail Supported CSS Properties & Media Queries](https://developers.google.com/gmail/design/reference/supported_css).
-->
<style amp-custom>
.emailbody {
padding: 16px;
}
.helloworld {
font-family: Helvetica;
color: red;
font-size: 24px;
padding-bottom: 8px;
}
.images {
max-width: 100%;
}
</style>
<!--
Note: The entire `<style>` tag cannot exceed 75,000 bytes. The validator will check for this.
-->
<!-- -->
</head>
<!-- ## Body -->
<!-- -->
<body>
<div class="emailbody">
<!--
Just like in AMP web pages, most HTML tags can be used directly.
-->
<h1 class="helloworld">Hello!</h1>
<!--
Certain tags, such as the `<img>` tag, are replaced with equivalent or slightly enhanced custom AMP HTML tags (see [HTML Tags in the specification](https://github.com/ampproject/amphtml/blob/master/spec/amp-html-format.md)).
-->
<amp-img src="https://amp.dev/static/samples/img/amp.jpg" width="800" height="600" layout="responsive"></amp-img>
<!--
Important: URLs most use absolute paths in AMP for Email.

Since we imported the `amp-carousel` component in the header as example, let's try it here.
-->
<amp-carousel width="800" height="600" layout="responsive" type="slides" controls>
<amp-img src="https://amp.dev/static/samples/img/image1.jpg" width="800" height="600" alt="a sample image"></amp-img>
<amp-img src="https://amp.dev/static/samples/img/image2.jpg" width="800" height="600" alt="another sample image"></amp-img>
<amp-img src="https://amp.dev/static/samples/img/image3.jpg" width="800" height="600" alt="and another sample image"></amp-img>
</amp-carousel>
</div>
</body>
</html>
'''

message = Mail(
from_email='[email protected]',
modernwarfareuplink marked this conversation as resolved.
Show resolved Hide resolved
to_emails='[email protected]',
subject='Sending with Twilio SendGrid is Fun',
html_content='<strong>and easy to do anywhere, even with Python</strong>')
modernwarfareuplink marked this conversation as resolved.
Show resolved Hide resolved
try:
sg = SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY'))
response = sg.send(message)
print(response.status_code)
print(response.body)
print(response.headers)
except Exception as e:
print(e.message)
```