mail.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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. from __future__ import print_function, unicode_literals
  17. import six
  18. import smtplib
  19. import sys
  20. from mediagoblin import mg_globals, messages
  21. from mediagoblin._compat import MIMEText
  22. from mediagoblin.tools import common
  23. ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  24. ### Special email test stuff begins HERE
  25. ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  26. # We have two "test inboxes" here:
  27. #
  28. # EMAIL_TEST_INBOX:
  29. # ----------------
  30. # If you're writing test views, you'll probably want to check this.
  31. # It contains a list of MIMEText messages.
  32. #
  33. # EMAIL_TEST_MBOX_INBOX:
  34. # ----------------------
  35. # This collects the messages from the FakeMhost inbox. It's reslly
  36. # just here for testing the send_email method itself.
  37. #
  38. # Anyway this contains:
  39. # - from
  40. # - to: a list of email recipient addresses
  41. # - message: not just the body, but the whole message, including
  42. # headers, etc.
  43. #
  44. # ***IMPORTANT!***
  45. # ----------------
  46. # Before running tests that call functions which send email, you should
  47. # always call _clear_test_inboxes() to "wipe" the inboxes clean.
  48. EMAIL_TEST_INBOX = []
  49. EMAIL_TEST_MBOX_INBOX = []
  50. class FakeMhost(object):
  51. """
  52. Just a fake mail host so we can capture and test messages
  53. from send_email
  54. """
  55. def login(self, *args, **kwargs):
  56. pass
  57. def sendmail(self, from_addr, to_addrs, message):
  58. EMAIL_TEST_MBOX_INBOX.append(
  59. {'from': from_addr,
  60. 'to': to_addrs,
  61. 'message': message})
  62. def starttls(self):
  63. raise smtplib.SMTPException("No STARTTLS here")
  64. def _clear_test_inboxes():
  65. global EMAIL_TEST_INBOX
  66. global EMAIL_TEST_MBOX_INBOX
  67. EMAIL_TEST_INBOX = []
  68. EMAIL_TEST_MBOX_INBOX = []
  69. ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  70. ### </Special email test stuff>
  71. ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  72. def send_email(from_addr, to_addrs, subject, message_body):
  73. """
  74. Simple email sending wrapper, use this so we can capture messages
  75. for unit testing purposes.
  76. Args:
  77. - from_addr: address you're sending the email from
  78. - to_addrs: list of recipient email addresses
  79. - subject: subject of the email
  80. - message_body: email body text
  81. """
  82. if common.TESTS_ENABLED or mg_globals.app_config['email_debug_mode']:
  83. mhost = FakeMhost()
  84. elif not mg_globals.app_config['email_debug_mode']:
  85. if mg_globals.app_config['email_smtp_use_ssl']:
  86. smtp_init = smtplib.SMTP_SSL
  87. else:
  88. smtp_init = smtplib.SMTP
  89. mhost = smtp_init(
  90. mg_globals.app_config['email_smtp_host'],
  91. mg_globals.app_config['email_smtp_port'])
  92. # SMTP.__init__ Issues SMTP.connect implicitly if host
  93. if not mg_globals.app_config['email_smtp_host']: # e.g. host = ''
  94. mhost.connect() # We SMTP.connect explicitly
  95. try:
  96. mhost.starttls()
  97. except smtplib.SMTPException:
  98. # Only raise an exception if we're forced to
  99. if mg_globals.app_config['email_smtp_force_starttls']:
  100. six.reraise(*sys.exc_info())
  101. if ((not common.TESTS_ENABLED)
  102. and (mg_globals.app_config['email_smtp_user']
  103. or mg_globals.app_config['email_smtp_pass'])):
  104. mhost.login(
  105. mg_globals.app_config['email_smtp_user'],
  106. mg_globals.app_config['email_smtp_pass'])
  107. message = MIMEText(message_body.encode('utf-8'), 'plain', 'utf-8')
  108. message['Subject'] = subject
  109. message['From'] = from_addr
  110. message['To'] = ', '.join(to_addrs)
  111. if common.TESTS_ENABLED:
  112. EMAIL_TEST_INBOX.append(message)
  113. elif mg_globals.app_config['email_debug_mode']:
  114. print("===== Email =====")
  115. print("From address: %s" % message['From'])
  116. print("To addresses: %s" % message['To'])
  117. print("Subject: %s" % message['Subject'])
  118. print("-- Body: --")
  119. print(message.get_payload(decode=True))
  120. return mhost.sendmail(from_addr, to_addrs, message.as_string())
  121. def normalize_email(email):
  122. """return case sensitive part, lower case domain name
  123. :returns: None in case of broken email addresses"""
  124. try:
  125. em_user, em_dom = email.split('@', 1)
  126. except ValueError:
  127. # email contained no '@'
  128. return None
  129. email = "@".join((em_user, em_dom.lower()))
  130. return email
  131. def email_debug_message(request):
  132. """
  133. If the server is running in email debug mode (which is
  134. the current default), give a debug message to the user
  135. so that they have an idea where to find their email.
  136. """
  137. if mg_globals.app_config['email_debug_mode']:
  138. # DEBUG message, no need to translate
  139. messages.add_message(request, messages.DEBUG,
  140. "This instance is running in email debug mode. "
  141. "The email will be on the console of the server process.")