/usr/lib/python2.7/dist-packages/quixote/sendmail.py is in python-quixote1 1.2-6.
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 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | """quixote.sendmail
$HeadURL: svn+ssh://svn/repos/trunk/quixote/sendmail.py $
$Id: sendmail.py 25234 2004-09-30 17:36:19Z nascheme $
Tools for sending mail from Quixote applications.
"""
# created 2001/08/27, Greg Ward (with a long and complicated back-story)
__revision__ = "$Id: sendmail.py 25234 2004-09-30 17:36:19Z nascheme $"
import re
from types import ListType, TupleType, StringType
from smtplib import SMTP
rfc822_specials_re = re.compile(r'[\(\)\<\>\@\,\;\:\\\"\.\[\]]')
class RFC822Mailbox:
"""
In RFC 822, a "mailbox" is either a bare e-mail address or a bare
e-mail address coupled with a chunk of text, most often someone's
name. Eg. the following are all "mailboxes" in the RFC 822 grammar:
luser@example.com
Joe Luser <luser@example.com>
Paddy O'Reilly <paddy@example.ie>
"Smith, John" <smith@example.com>
Dick & Jane <dickjane@example.net>
"Tom, Dick, & Harry" <tdh@example.org>
This class represents an (addr_spec, real_name) pair and takes care
of quoting the real_name according to RFC 822's rules for you.
Just use the format() method and it will spit out a properly-
quoted RFC 822 "mailbox".
"""
def __init__(self, *args):
"""RFC822Mailbox(addr_spec : string, name : string)
RFC822Mailbox(addr_spec : string)
RFC822Mailbox((addr_spec : string, name : string))
RFC822Mailbox((addr_spec : string))
Create a new RFC822Mailbox instance. The variety of call
signatures is purely for your convenience.
"""
if (len(args) == 1 and type(args[0]) is TupleType):
args = args[0]
if len(args) == 1:
addr_spec = args[0]
real_name = None
elif len(args) == 2:
(addr_spec, real_name) = args
else:
raise TypeError(
"invalid number of arguments: "
"expected 1 or 2 strings or "
"a tuple of 1 or 2 strings")
self.addr_spec = addr_spec
self.real_name = real_name
def __str__(self):
return self.addr_spec
def __repr__(self):
return "<%s at %x: %s>" % (self.__class__.__name__, id(self), self)
def format(self):
if self.real_name and rfc822_specials_re.search(self.real_name):
return '"%s" <%s>' % (self.real_name.replace('"', '\\"'),
self.addr_spec)
elif self.real_name:
return '%s <%s>' % (self.real_name, self.addr_spec)
else:
return self.addr_spec
def _ensure_mailbox(s):
"""_ensure_mailbox(s : string |
(string,) |
(string, string) |
RFC822Mailbox |
None)
-> RFC822Mailbox | None
If s is a string, or a tuple of 1 or 2 strings, returns an
RFC822Mailbox encapsulating them as an addr_spec and real_name. If
s is already an RFC822Mailbox, returns s. If s is None, returns
None.
"""
if s is None or isinstance(s, RFC822Mailbox):
return s
else:
return RFC822Mailbox(s)
# Maximum number of recipients that will be explicitly listed in
# any single message header. Eg. if MAX_HEADER_RECIPIENTS is 10,
# there could be up to 10 "To" recipients and 10 "CC" recipients
# explicitly listed in the message headers.
MAX_HEADER_RECIPIENTS = 10
def _add_recip_headers(headers, field_name, addrs):
if not addrs:
return
addrs = [addr.format() for addr in addrs]
if len(addrs) == 1:
headers.append("%s: %s" % (field_name, addrs[0]))
elif len(addrs) <= MAX_HEADER_RECIPIENTS:
headers.append("%s: %s," % (field_name, addrs[0]))
for addr in addrs[1:-1]:
headers.append(" %s," % addr)
headers.append(" %s" % addrs[-1])
else:
headers.append("%s: (long recipient list suppressed) : ;" % field_name)
def sendmail(subject, msg_body, to_addrs,
from_addr=None, cc_addrs=None,
extra_headers=None,
smtp_sender=None, smtp_recipients=None,
config=None):
"""sendmail(subject : string,
msg_body : string,
to_addrs : [email_address],
from_addr : email_address = config.MAIL_SENDER,
cc_addrs : [email_address] = None,
extra_headers : [string] = None,
smtp_sender : email_address = (derived from from_addr)
smtp_recipients : [email_address] = (derived from to_addrs),
config : quixote.config.Config = (current publisher's config)):
Send an email message to a list of recipients via a local SMTP
server. In normal use, you supply a list of primary recipient
e-mail addresses in 'to_addrs', an optional list of secondary
recipient addresses in 'cc_addrs', and a sender address in
'from_addr'. sendmail() then constructs a message using those
addresses, 'subject', and 'msg_body', and mails the message to every
recipient address. (Specifically, it connects to the mail server
named in the MAIL_SERVER config variable -- default "localhost" --
and instructs the server to send the message to every recipient
address in 'to_addrs' and 'cc_addrs'.)
'from_addr' is optional because web applications often have a common
e-mail sender address, such as "webmaster@example.com". Just set
the Quixote config variable MAIL_FROM, and it will be used as the
default sender (both header and envelope) for all e-mail sent by
sendmail().
E-mail addresses can be specified a number of ways. The most
efficient is to supply instances of RFC822Mailbox, which bundles a
bare e-mail address (aka "addr_spec" from the RFC 822 grammar) and
real name together in a readily-formattable object. You can also
supply an (addr_spec, real_name) tuple, or an addr_spec on its own.
The latter two are converted into RFC822Mailbox objects for
formatting, which is why it may be more efficient to construct
RFC822Mailbox objects yourself.
Thus, the following are all equivalent in terms of who gets the
message:
sendmail(to_addrs=["joe@example.com"], ...)
sendmail(to_addrs=[("joe@example.com", "Joe User")], ...)
sendmail(to_addrs=[RFC822Mailbox("joe@example.com", "Joe User")], ...)
...although the "To" header will be slightly different. In the
first case, it will be
To: joe@example.com
while in the other two, it will be:
To: Joe User <joe@example.com>
which is a little more user-friendly.
In more advanced usage, you might wish to specify the SMTP sender
and recipient addresses separately. For example, if you want your
application to send mail to users that looks like it comes from a
real human being, but you don't want that human being to get the
bounce messages from the mailing, you might do this:
sendmail(to_addrs=user_list,
...,
from_addr=("realuser@example.com", "A Real User"),
smtp_sender="postmaster@example.com")
End users will see mail from "A Real User <realuser@example.com>" in
their inbox, but bounces will go to postmaster@example.com.
One use of different header and envelope recipients is for
testing/debugging. If you want to test that your application is
sending the right mail to bigboss@example.com without filling
bigboss' inbox with dross, you might do this:
sendmail(to_addrs=["bigboss@example.com"],
...,
smtp_recipients=["developers@example.com"])
This is so useful that it's a Quixote configuration option: just set
MAIL_DEBUG_ADDR to (eg.) "developers@example.com", and every message
that sendmail() would send out is diverted to the debug address.
Generally raises an exception on any SMTP errors; see smtplib (in
the standard library documentation) for details.
"""
if config is None:
from quixote import get_publisher
config = get_publisher().config
if not isinstance(to_addrs, ListType):
raise TypeError("'to_addrs' must be a list")
if not (cc_addrs is None or isinstance(cc_addrs, ListType)):
raise TypeError("'cc_addrs' must be a list or None")
# Make sure we have a "From" address
if from_addr is None:
from_addr = config.mail_from
if from_addr is None:
raise RuntimeError(
"no from_addr supplied, and MAIL_FROM not set in config file")
# Ensure all of our addresses are really RFC822Mailbox objects.
from_addr = _ensure_mailbox(from_addr)
to_addrs = map(_ensure_mailbox, to_addrs)
if cc_addrs:
cc_addrs = map(_ensure_mailbox, cc_addrs)
# Start building the message headers.
headers = ["From: %s" % from_addr.format(),
"Subject: %s" % subject]
_add_recip_headers(headers, "To", to_addrs)
if cc_addrs:
_add_recip_headers(headers, "Cc", cc_addrs)
if extra_headers:
headers.extend(extra_headers)
if config.mail_debug_addr:
debug1 = ("[debug mode, message actually sent to %s]\n"
% config.mail_debug_addr)
if smtp_recipients:
debug2 = ("[original SMTP recipients: %s]\n"
% ", ".join(smtp_recipients))
else:
debug2 = ""
sep = ("-"*72) + "\n"
msg_body = debug1 + debug2 + sep + msg_body
smtp_recipients = [config.mail_debug_addr]
if smtp_sender is None:
smtp_sender = from_addr.addr_spec
else:
smtp_sender = _ensure_mailbox(smtp_sender).addr_spec
if smtp_recipients is None:
smtp_recipients = [addr.addr_spec for addr in to_addrs]
if cc_addrs:
smtp_recipients.extend([addr.addr_spec for addr in cc_addrs])
else:
smtp_recipients = [_ensure_mailbox(recip).addr_spec
for recip in smtp_recipients]
message = "\n".join(headers) + "\n\n" + msg_body
# Sanity checks
assert type(smtp_sender) is StringType, \
"smtp_sender not a string: %r" % (smtp_sender,)
assert (type(smtp_recipients) is ListType and
map(type, smtp_recipients) == [StringType]*len(smtp_recipients)), \
"smtp_recipients not a list of strings: %r" % (smtp_recipients,)
smtp = SMTP(config.mail_server)
smtp.sendmail(smtp_sender, smtp_recipients, message)
smtp.quit()
# sendmail ()
|