docs: Document video resolution config.
[mediagoblin.git] / mediagoblin / tools / mail.py
... / ...
CommitLineData
1# GNU MediaGoblin -- federated, autonomous media hosting
2# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
3#
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU Affero General Public License as published by
6# the Free Software Foundation, either version 3 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Affero General Public License for more details.
13#
14# You should have received a copy of the GNU Affero General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17from __future__ import print_function, unicode_literals
18
19import socket
20import logging
21import six
22import smtplib
23import sys
24from mediagoblin import mg_globals, messages
25from mediagoblin._compat import MIMEText
26from mediagoblin.tools import common
27
28### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29### Special email test stuff begins HERE
30### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
31
32# We have two "test inboxes" here:
33#
34# EMAIL_TEST_INBOX:
35# ----------------
36# If you're writing test views, you'll probably want to check this.
37# It contains a list of MIMEText messages.
38#
39# EMAIL_TEST_MBOX_INBOX:
40# ----------------------
41# This collects the messages from the FakeMhost inbox. It's reslly
42# just here for testing the send_email method itself.
43#
44# Anyway this contains:
45# - from
46# - to: a list of email recipient addresses
47# - message: not just the body, but the whole message, including
48# headers, etc.
49#
50# ***IMPORTANT!***
51# ----------------
52# Before running tests that call functions which send email, you should
53# always call _clear_test_inboxes() to "wipe" the inboxes clean.
54
55EMAIL_TEST_INBOX = []
56EMAIL_TEST_MBOX_INBOX = []
57
58
59class MailError(Exception):
60 """ General exception for mail errors """
61
62
63class NoSMTPServerError(MailError):
64 pass
65
66
67class FakeMhost(object):
68 """
69 Just a fake mail host so we can capture and test messages
70 from send_email
71 """
72 def login(self, *args, **kwargs):
73 pass
74
75 def sendmail(self, from_addr, to_addrs, message):
76 EMAIL_TEST_MBOX_INBOX.append(
77 {'from': from_addr,
78 'to': to_addrs,
79 'message': message})
80
81 def starttls(self):
82 raise smtplib.SMTPException("No STARTTLS here")
83
84def _clear_test_inboxes():
85 global EMAIL_TEST_INBOX
86 global EMAIL_TEST_MBOX_INBOX
87 EMAIL_TEST_INBOX = []
88 EMAIL_TEST_MBOX_INBOX = []
89
90
91### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
92### </Special email test stuff>
93### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
94
95def send_email(from_addr, to_addrs, subject, message_body):
96 """
97 Simple email sending wrapper, use this so we can capture messages
98 for unit testing purposes.
99
100 Args:
101 - from_addr: address you're sending the email from
102 - to_addrs: list of recipient email addresses
103 - subject: subject of the email
104 - message_body: email body text
105 """
106 if common.TESTS_ENABLED or mg_globals.app_config['email_debug_mode']:
107 mhost = FakeMhost()
108 elif not mg_globals.app_config['email_debug_mode']:
109 if mg_globals.app_config['email_smtp_use_ssl']:
110 smtp_init = smtplib.SMTP_SSL
111 else:
112 smtp_init = smtplib.SMTP
113
114 try:
115 mhost = smtp_init(
116 mg_globals.app_config['email_smtp_host'],
117 mg_globals.app_config['email_smtp_port'])
118 except socket.error as original_error:
119 error_message = "Couldn't contact mail server on <{}>:<{}>".format(
120 mg_globals.app_config['email_smtp_host'],
121 mg_globals.app_config['email_smtp_port'])
122 logging.debug(original_error)
123 raise NoSMTPServerError(error_message)
124
125 # SMTP.__init__ Issues SMTP.connect implicitly if host
126 if not mg_globals.app_config['email_smtp_host']: # e.g. host = ''
127 try:
128 mhost.connect() # We SMTP.connect explicitly
129 except socket.error as original_error:
130 error_message = "Couldn't contact mail server on <{}>:<{}>".format(
131 mg_globals.app_config['email_smtp_host'],
132 mg_globals.app_config['email_smtp_port'])
133 logging.debug(original_error)
134 raise NoSMTPServerError(error_message)
135
136 try:
137 mhost.starttls()
138 except smtplib.SMTPException:
139 # Only raise an exception if we're forced to
140 if mg_globals.app_config['email_smtp_force_starttls']:
141 six.reraise(*sys.exc_info())
142
143 if ((not common.TESTS_ENABLED)
144 and (mg_globals.app_config['email_smtp_user']
145 or mg_globals.app_config['email_smtp_pass'])):
146 mhost.login(
147 mg_globals.app_config['email_smtp_user'],
148 mg_globals.app_config['email_smtp_pass'])
149
150 message = MIMEText(message_body.encode('utf-8'), 'plain', 'utf-8')
151 message['Subject'] = subject
152 message['From'] = from_addr
153 message['To'] = ', '.join(to_addrs)
154
155 if common.TESTS_ENABLED:
156 EMAIL_TEST_INBOX.append(message)
157
158 elif mg_globals.app_config['email_debug_mode']:
159 print("===== Email =====")
160 print("From address: %s" % message['From'])
161 print("To addresses: %s" % message['To'])
162 print("Subject: %s" % message['Subject'])
163 print("-- Body: --")
164 print(message_body)
165
166 return mhost.sendmail(from_addr, to_addrs, message.as_string())
167
168
169def normalize_email(email):
170 """return case sensitive part, lower case domain name
171
172 :returns: None in case of broken email addresses"""
173 try:
174 em_user, em_dom = email.split('@', 1)
175 except ValueError:
176 # email contained no '@'
177 return None
178 email = "@".join((em_user, em_dom.lower()))
179 return email
180
181
182def email_debug_message(request):
183 """
184 If the server is running in email debug mode (which is
185 the current default), give a debug message to the user
186 so that they have an idea where to find their email.
187 """
188 if mg_globals.app_config['email_debug_mode']:
189 # DEBUG message, no need to translate
190 messages.add_message(
191 request,
192 messages.DEBUG,
193 "This instance is running in email debug mode. "
194 "The email will be on the console of the server process.")