Add email provider for sending emails.

This commit is contained in:
Brian Simpson
2015-08-24 20:28:07 -04:00
parent dc36addb0d
commit c65a8e1897
6 changed files with 191 additions and 0 deletions

View File

@@ -269,6 +269,15 @@ statsd_sample_rate = 1.0
# percentage of stats for sampling (0-100)
stats_sample_rate = 1
############################################ EMAIL
# which email provider to use
# options are:
# null - no email
# mailgun - use mailgun as configured for reddit.com
# or write your own!
email_provider = null
mailgun_domain =
mailgun_api_base_url =
############################################ MEDIA STORAGE
# which backend provider to use for media (thumbnails, subreddit stylesheets,

View File

@@ -534,6 +534,12 @@ class Globals(object):
"r2.provider.image_resizing",
self.image_resizing_provider,
)
self.email_provider = select_provider(
self.config,
self.pkg_resources_working_set,
"r2.provider.email",
self.email_provider,
)
self.startup_timer.intermediate("providers")
################# CONFIGURATION

View File

@@ -0,0 +1,55 @@
# The contents of this file are subject to the Common Public Attribution
# License Version 1.0. (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
# License Version 1.1, but Sections 14 and 15 have been added to cover use of
# software over a computer network and provide for limited attribution for the
# Original Developer. In addition, Exhibit A has been modified to be consistent
# with Exhibit B.
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
#
# The Original Code is reddit.
#
# The Original Developer is the Initial Developer. The Initial Developer of
# the Original Code is reddit Inc.
#
# All portions of the code written by reddit are Copyright (c) 2006-2015 reddit
# Inc. All Rights Reserved.
###############################################################################
class EmailProvider(object):
"""Provider for sending emails.
"""
def send_email(self, to_address, from_address, subject, text, reply_to,
parent_email_id=None, other_email_ids=None):
"""Send an email.
`to_address` is a string or list of string email addresses.
`from_address` is a email address.
`subject` is the email's subject.
`text` is the text of the email.
`reply_to` is the reply-to address, which will be sent as the "Reply-To"
email header.
`parent_email_id` is the Message-Id of the email this is a reply to (if
any). This is sent as the "In-Reply-To" email header.
`other_email_ids` is a list of Message-Ids of emails in the conversation
and including `parent_email_id`. This will be converted to a space
delimited string and sent as the "References" email header.
The return value is the Message-Id of the sent email.
"""
raise NotImplementedError
class EmailSendError(Exception): pass

View File

@@ -0,0 +1,85 @@
# The contents of this file are subject to the Common Public Attribution
# License Version 1.0. (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
# License Version 1.1, but Sections 14 and 15 have been added to cover use of
# software over a computer network and provide for limited attribution for the
# Original Developer. In addition, Exhibit A has been modified to be consistent
# with Exhibit B.
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
#
# The Original Code is reddit.
#
# The Original Developer is the Initial Developer. The Initial Developer of
# the Original Code is reddit Inc.
#
# All portions of the code written by reddit are Copyright (c) 2006-2015 reddit
# Inc. All Rights Reserved.
###############################################################################
import json
import requests
from r2.lib.configparse import ConfigValue
from r2.lib.providers.email import (
EmailProvider,
EmailSendError,
)
from r2.lib.utils import tup
class MailgunEmailProvider(EmailProvider):
"""A provider that uses mailgun to send emails."""
config = {
ConfigValue.str: [
"mailgun_api_base_url",
],
# This also requires the secret "mailgun_api_key"
}
def send_email(self, to_address, from_address, subject, text, reply_to,
parent_email_id=None, other_email_ids=None):
from pylons import app_globals as g
message_post_url = "/".join((
g.mailgun_api_base_url, g.mailgun_domain, "messages"))
to_address = tup(to_address)
parent_email_id = parent_email_id or ''
other_email_ids = other_email_ids or []
response = requests.post(
message_post_url,
auth=("api", g.secrets['mailgun_api_key']),
data={
"from": from_address,
"to": to_address,
"subject": subject,
"text": text,
"o:tracking": False, # disable link rewriting
"h:Reply-To": reply_to,
"h:In-Reply-To": parent_email_id,
"h:References": " ".join(other_email_ids),
},
)
if response.status_code != 200:
msg = "mailgun sending email failed {status}: {text}".format(
status=response.status_code, text=response.text)
raise EmailSendError(msg)
try:
body = json.loads(response.text)
except ValueError:
msg = "mailgun sending email bad response {status}: {text}".format(
status=response.status_code, text=response.text)
raise EmailSendError(msg)
email_id = body["id"]
return email_id

View File

@@ -0,0 +1,33 @@
# The contents of this file are subject to the Common Public Attribution
# License Version 1.0. (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
# License Version 1.1, but Sections 14 and 15 have been added to cover use of
# software over a computer network and provide for limited attribution for the
# Original Developer. In addition, Exhibit A has been modified to be consistent
# with Exhibit B.
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
#
# The Original Code is reddit.
#
# The Original Developer is the Initial Developer. The Initial Developer of
# the Original Code is reddit Inc.
#
# All portions of the code written by reddit are Copyright (c) 2006-2015 reddit
# Inc. All Rights Reserved.
###############################################################################
from r2.lib.providers.email import EmailProvider
class NullEmailProvider(EmailProvider):
"""A no-op email provider.
"""
def send_email(self, to_address, from_address, subject, text, reply_to,
parent_email_id=None, other_email_ids=None):
return None

View File

@@ -131,5 +131,8 @@ setup(
imgix = r2.lib.providers.image_resizing.imgix:ImgixImageResizingProvider
no_op = r2.lib.providers.image_resizing.no_op:NoOpImageResizingProvider
unsplashit = r2.lib.providers.image_resizing.unsplashit:UnsplashitImageResizingProvider
[r2.provider.email]
null = r2.lib.providers.email.null:NullEmailProvider
mailgun = r2.lib.providers.email.mailgun:MailgunEmailProvider
""",
)