1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
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.
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.
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/>.
17 from __future__
import print_function
, unicode_literals
24 from mediagoblin
import mg_globals
, messages
25 from mediagoblin
._compat
import MIMEText
26 from mediagoblin
.tools
import common
28 ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29 ### Special email test stuff begins HERE
30 ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32 # We have two "test inboxes" here:
36 # If you're writing test views, you'll probably want to check this.
37 # It contains a list of MIMEText messages.
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.
44 # Anyway this contains:
46 # - to: a list of email recipient addresses
47 # - message: not just the body, but the whole message, including
52 # Before running tests that call functions which send email, you should
53 # always call _clear_test_inboxes() to "wipe" the inboxes clean.
56 EMAIL_TEST_MBOX_INBOX
= []
59 class MailError(Exception):
60 """ General exception for mail errors """
63 class NoSMTPServerError(MailError
):
67 class FakeMhost(object):
69 Just a fake mail host so we can capture and test messages
72 def login(self
, *args
, **kwargs
):
75 def sendmail(self
, from_addr
, to_addrs
, message
):
76 EMAIL_TEST_MBOX_INBOX
.append(
82 raise smtplib
.SMTPException("No STARTTLS here")
84 def _clear_test_inboxes():
85 global EMAIL_TEST_INBOX
86 global EMAIL_TEST_MBOX_INBOX
88 EMAIL_TEST_MBOX_INBOX
= []
91 ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
92 ### </Special email test stuff>
93 ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
95 def send_email(from_addr
, to_addrs
, subject
, message_body
):
97 Simple email sending wrapper, use this so we can capture messages
98 for unit testing purposes.
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
106 if common
.TESTS_ENABLED
or mg_globals
.app_config
['email_debug_mode']:
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
112 smtp_init
= smtplib
.SMTP
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
)
125 # SMTP.__init__ Issues SMTP.connect implicitly if host
126 if not mg_globals
.app_config
['email_smtp_host']: # e.g. host = ''
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
)
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())
143 if ((not common
.TESTS_ENABLED
)
144 and (mg_globals
.app_config
['email_smtp_user']
145 or mg_globals
.app_config
['email_smtp_pass'])):
147 mg_globals
.app_config
['email_smtp_user'],
148 mg_globals
.app_config
['email_smtp_pass'])
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
)
155 if common
.TESTS_ENABLED
:
156 EMAIL_TEST_INBOX
.append(message
)
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'])
166 return mhost
.sendmail(from_addr
, to_addrs
, message
.as_string())
169 def normalize_email(email
):
170 """return case sensitive part, lower case domain name
172 :returns: None in case of broken email addresses"""
174 em_user
, em_dom
= email
.split('@', 1)
176 # email contained no '@'
178 email
= "@".join((em_user
, em_dom
.lower()))
182 def email_debug_message(request
):
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.
188 if mg_globals
.app_config
['email_debug_mode']:
189 # DEBUG message, no need to translate
190 messages
.add_message(
193 "This instance is running in email debug mode. "
194 "The email will be on the console of the server process.")