1
# -*- coding: iso-8859-1 -*-
3
MoinMoin - email helper functions
5
@copyright: 2003 Juergen Hermann <jh@web.de>,
6
2008 MoinMoin:ThomasWaldmann
7
@license: GNU GPL, see COPYING for details.
11
from email.Header import Header
13
from MoinMoin import log
14
logging = log.getLogger(__name__)
16
from MoinMoin import config
18
_transdict = {"AT": "@", "DOT": ".", "DASH": "-"}
21
def encodeAddress(address, charset):
22
""" Encode email address to enable non ascii names
24
e.g. '"J�rgen Hermann" <jh@web.de>'. According to the RFC, the name
25
part should be encoded, the address should not.
27
@param address: email address, possibly using '"name" <address>' format
28
@type address: unicode
29
@param charset: specifying both the charset and the encoding, e.g
30
quoted printable or base64.
31
@type charset: email.Charset.Charset instance
33
@return: encoded address
35
composite = re.compile(r'(?P<phrase>.+)(?P<angle_addr>\<.*\>)', re.UNICODE)
36
match = composite.match(address)
38
phrase = match.group('phrase').encode(config.charset)
39
phrase = str(Header(phrase, charset))
40
angle_addr = match.group('angle_addr').encode(config.charset)
41
return phrase + angle_addr
43
return address.encode(config.charset)
46
def sendmail(request, to, subject, text, mail_from=None):
47
""" Create and send a text/plain message
49
Return a tuple of success or error indicator and message.
51
@param request: the request object
52
@param to: recipients (list)
53
@param subject: subject of email (unicode)
54
@param text: email body text (unicode)
55
@param mail_from: override default mail_from
56
@type mail_from: unicode
58
@return: (is_ok, Description of error or OK message)
60
import smtplib, socket
61
from email.Message import Message
62
from email.Charset import Charset, QP
63
from email.Utils import formatdate, make_msgid
67
mail_from = mail_from or cfg.mail_from
68
subject = subject.encode(config.charset)
70
# Create a text/plain body using CRLF (see RFC2822)
71
text = text.replace(u'\n', u'\r\n')
72
text = text.encode(config.charset)
74
# Create a message using config.charset and quoted printable
75
# encoding, which should be supported better by mail clients.
76
# TODO: check if its really works better for major mail clients
78
charset = Charset(config.charset)
79
charset.header_encoding = QP
80
charset.body_encoding = QP
81
msg.set_charset(charset)
83
# work around a bug in python 2.4.3 and above:
85
if msg.as_string().endswith('='):
86
text = charset.body_encode(text)
90
# Create message headers
91
# Don't expose emails addreses of the other subscribers, instead we
92
# use the same mail_from, e.g. u"J�rgen Wiki <noreply@mywiki.org>"
93
address = encodeAddress(mail_from, charset)
96
msg['Date'] = formatdate()
97
msg['Message-ID'] = make_msgid()
98
msg['Subject'] = Header(subject, charset)
100
if cfg.mail_sendmail:
101
# Set the BCC. This will be stripped later by sendmail.
102
msg['BCC'] = ','.join(to)
103
# Set Return-Path so that it isn't set (generally incorrectly) for us.
104
msg['Return-Path'] = address
107
if not cfg.mail_sendmail:
109
logging.debug("trying to send mail (smtp) via smtp server '%s'" % cfg.mail_smarthost)
110
host, port = (cfg.mail_smarthost + ':25').split(':')[:2]
111
server = smtplib.SMTP(host, int(port))
113
#server.set_debuglevel(1)
115
user, pwd = cfg.mail_login.split()
118
if server.has_extn('starttls'):
121
logging.debug("tls connection to smtp server established")
123
logging.debug("could not establish a tls connection to smtp server, continuing without tls")
124
logging.debug("trying to log in to smtp server using account '%s'" % user)
125
server.login(user, pwd)
126
server.sendmail(mail_from, to, msg.as_string())
130
except AttributeError:
131
# in case the connection failed, SMTP has no "sock" attribute
133
except smtplib.SMTPException, e:
134
logging.exception("smtp mail failed with an exception.")
136
except (os.error, socket.error), e:
137
logging.exception("smtp mail failed with an exception.")
138
return (0, _("Connection to mailserver '%(server)s' failed: %(reason)s") % {
139
'server': cfg.mail_smarthost,
144
logging.debug("trying to send mail (sendmail)")
145
sendmailp = os.popen(cfg.mail_sendmail, "w")
146
# msg contains everything we need, so this is a simple write
147
sendmailp.write(msg.as_string())
148
sendmail_status = sendmailp.close()
150
logging.error("sendmail failed with status: %s" % str(sendmail_status))
151
return (0, str(sendmail_status))
153
logging.exception("sendmail failed with an exception.")
154
return (0, _("Mail not sent"))
156
logging.debug("Mail sent OK")
157
return (1, _("Mail sent OK"))
160
def decodeSpamSafeEmail(address):
161
""" Decode obfuscated email address to standard email address
163
Decode a spam-safe email address in `address` by applying the
166
Known all-uppercase words and their translation:
171
Any unknown all-uppercase words simply get stripped.
172
Use that to make it even harder for spam bots!
174
Blanks (spaces) simply get stripped.
176
@param address: obfuscated email address string
178
@return: decoded email address
182
# words are separated by blanks
183
for word in address.split():
184
# is it all-uppercase?
185
if word.isalpha() and word == word.upper():
186
# strip unknown CAPS words
187
word = _transdict.get(word, '')
190
# return concatenated parts
191
return ''.join(email)