/usr/share/pyshared/MoinMoin/mail/sendmail.py is in python-moinmoin 1.9.3-1ubuntu2.3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | # -*- coding: iso-8859-1 -*-
"""
MoinMoin - email helper functions
@copyright: 2003 Juergen Hermann <jh@web.de>,
2008-2009 MoinMoin:ThomasWaldmann
@license: GNU GPL, see COPYING for details.
"""
import os, re
from email.Header import Header
from MoinMoin import log
logging = log.getLogger(__name__)
from MoinMoin import config
_transdict = {"AT": "@", "DOT": ".", "DASH": "-"}
def encodeAddress(address, charset):
""" Encode email address to enable non ascii names
e.g. '"Jürgen Hermann" <jh@web.de>'. According to the RFC, the name
part should be encoded, the address should not.
@param address: email address, possibly using '"name" <address>' format
@type address: unicode
@param charset: specifying both the charset and the encoding, e.g
quoted printable or base64.
@type charset: email.Charset.Charset instance
@rtype: string
@return: encoded address
"""
assert isinstance(address, unicode)
composite = re.compile(r'(?P<phrase>.*?)(?P<blanks>\s*)\<(?P<addr>.*)\>', re.UNICODE)
match = composite.match(address)
if match:
phrase = match.group('phrase')
try:
str(phrase) # is it pure ascii?
except UnicodeEncodeError:
phrase = phrase.encode(config.charset)
phrase = Header(phrase, charset)
blanks = match.group('blanks')
addr = match.group('addr')
if phrase:
return "%s%s<%s>" % (str(phrase), str(blanks), str(addr))
else:
return str(addr)
else:
# a pure email address, should encode to ascii without problem
return str(address)
def sendmail(request, to, subject, text, mail_from=None):
""" Create and send a text/plain message
Return a tuple of success or error indicator and message.
@param request: the request object
@param to: recipients (list)
@param subject: subject of email (unicode)
@param text: email body text (unicode)
@param mail_from: override default mail_from
@type mail_from: unicode
@rtype: tuple
@return: (is_ok, Description of error or OK message)
"""
import smtplib, socket
from email.Message import Message
from email.Charset import Charset, QP
from email.Utils import formatdate, make_msgid
_ = request.getText
cfg = request.cfg
mail_from = mail_from or cfg.mail_from
logging.debug("send mail, from: %r, subj: %r" % (mail_from, subject))
logging.debug("send mail, to: %r" % (to, ))
if not to:
return (1, _("No recipients, nothing to do"))
subject = subject.encode(config.charset)
# Create a text/plain body using CRLF (see RFC2822)
text = text.replace(u'\n', u'\r\n')
text = text.encode(config.charset)
# Create a message using config.charset and quoted printable
# encoding, which should be supported better by mail clients.
# TODO: check if its really works better for major mail clients
msg = Message()
charset = Charset(config.charset)
charset.header_encoding = QP
charset.body_encoding = QP
msg.set_charset(charset)
# work around a bug in python 2.4.3 and above:
msg.set_payload('=')
if msg.as_string().endswith('='):
text = charset.body_encode(text)
msg.set_payload(text)
# Create message headers
# Don't expose emails addreses of the other subscribers, instead we
# use the same mail_from, e.g. u"Jürgen Wiki <noreply@mywiki.org>"
address = encodeAddress(mail_from, charset)
msg['From'] = address
msg['To'] = address
msg['Date'] = formatdate()
msg['Message-ID'] = make_msgid()
msg['Subject'] = Header(subject, charset)
# See RFC 3834 section 5:
msg['Auto-Submitted'] = 'auto-generated'
if cfg.mail_sendmail:
# Set the BCC. This will be stripped later by sendmail.
msg['BCC'] = ','.join(to)
# Set Return-Path so that it isn't set (generally incorrectly) for us.
msg['Return-Path'] = address
# Send the message
if not cfg.mail_sendmail:
try:
logging.debug("trying to send mail (smtp) via smtp server '%s'" % cfg.mail_smarthost)
host, port = (cfg.mail_smarthost + ':25').split(':')[:2]
server = smtplib.SMTP(host, int(port))
try:
#server.set_debuglevel(1)
if cfg.mail_login:
user, pwd = cfg.mail_login.split()
try: # try to do tls
server.ehlo()
if server.has_extn('starttls'):
server.starttls()
server.ehlo()
logging.debug("tls connection to smtp server established")
except:
logging.debug("could not establish a tls connection to smtp server, continuing without tls")
logging.debug("trying to log in to smtp server using account '%s'" % user)
server.login(user, pwd)
server.sendmail(mail_from, to, msg.as_string())
finally:
try:
server.quit()
except AttributeError:
# in case the connection failed, SMTP has no "sock" attribute
pass
except smtplib.SMTPException, e:
logging.exception("smtp mail failed with an exception.")
return (0, str(e))
except (os.error, socket.error), e:
logging.exception("smtp mail failed with an exception.")
return (0, _("Connection to mailserver '%(server)s' failed: %(reason)s") % {
'server': cfg.mail_smarthost,
'reason': str(e)
})
else:
try:
logging.debug("trying to send mail (sendmail)")
sendmailp = os.popen(cfg.mail_sendmail, "w")
# msg contains everything we need, so this is a simple write
sendmailp.write(msg.as_string())
sendmail_status = sendmailp.close()
if sendmail_status:
logging.error("sendmail failed with status: %s" % str(sendmail_status))
return (0, str(sendmail_status))
except:
logging.exception("sendmail failed with an exception.")
return (0, _("Mail not sent"))
logging.debug("Mail sent OK")
return (1, _("Mail sent OK"))
def encodeSpamSafeEmail(email_address, obfuscation_text=''):
""" Encodes a standard email address to an obfuscated address
@param email_address: mail address to encode.
Known characters and their all-uppercase words translation:
"." -> " DOT "
"@" -> " AT "
"-" -> " DASH "
@param obfuscation_text: optional text to obfuscate the email.
All characters in the string must be alphabetic
and they will be added in uppercase.
"""
address = email_address.lower()
# uppercase letters will be stripped by decodeSpamSafeEmail
for word, sign in _transdict.items():
address = address.replace(sign, ' %s ' % word)
if obfuscation_text.isalpha():
# is the obfuscation_text alphabetic
address = address.replace(' AT ', ' AT %s ' % obfuscation_text.upper())
return address
def decodeSpamSafeEmail(address):
""" Decode obfuscated email address to standard email address
Decode a spam-safe email address in `address` by applying the
following rules:
Known all-uppercase words and their translation:
"DOT" -> "."
"AT" -> "@"
"DASH" -> "-"
Any unknown all-uppercase words or an uppercase letter simply get stripped.
Use that to make it even harder for spam bots!
Blanks (spaces) simply get stripped.
@param address: obfuscated email address string
@rtype: string
@return: decoded email address
"""
email = []
# words are separated by blanks
for word in address.split():
# is it all-uppercase?
if word.isalpha() and word == word.upper():
# strip unknown CAPS words
word = _transdict.get(word, '')
email.append(word)
# return concatenated parts
return ''.join(email)
|