annotate examples/trac/trac/notification.py @ 39:93b4dcbafd7b trunk

Copy Trac to main branch.
author cmlenz
date Mon, 03 Jul 2006 18:53:27 +0000
parents
children
rev   line source
39
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
1 # -*- coding: utf-8 -*-
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
2 #
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
3 # Copyright (C) 2003-2006 Edgewall Software
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
4 # Copyright (C) 2003-2005 Daniel Lundin <daniel@edgewall.com>
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
5 # Copyright (C) 2005-2006 Emmanuel Blot <emmanuel.blot@free.fr>
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
6 # All rights reserved.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
7 #
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
8 # This software is licensed as described in the file COPYING, which
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
9 # you should have received as part of this distribution. The terms
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
10 # are also available at http://trac.edgewall.com/license.html.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
11 #
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
12 # This software consists of voluntary contributions made by many
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
13 # individuals. For the exact contribution history, see the revision
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
14 # history and logs, available at http://projects.edgewall.com/trac/.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
15 #
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
16
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
17 import time
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
18 import smtplib
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
19 import re
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
20
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
21 from trac import __version__
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
22 from trac.config import BoolOption, IntOption, Option
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
23 from trac.core import *
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
24 from trac.util.text import CRLF, wrap
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
25 from trac.web.chrome import Chrome
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
26 from trac.web.clearsilver import HDFWrapper
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
27 from trac.web.main import populate_hdf
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
28
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
29 MAXHEADERLEN = 76
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
30
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
31
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
32 class NotificationSystem(Component):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
33
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
34 smtp_enabled = BoolOption('notification', 'smtp_enabled', 'false',
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
35 """Enable SMTP (email) notification.""")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
36
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
37 smtp_server = Option('notification', 'smtp_server', 'localhost',
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
38 """SMTP server hostname to use for email notifications.""")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
39
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
40 smtp_port = IntOption('notification', 'smtp_port', 25,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
41 """SMTP server port to use for email notification.""")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
42
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
43 smtp_user = Option('notification', 'smtp_user', '',
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
44 """Username for SMTP server. (''since 0.9'').""")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
45
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
46 smtp_password = Option('notification', 'smtp_password', '',
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
47 """Password for SMTP server. (''since 0.9'').""")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
48
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
49 smtp_from = Option('notification', 'smtp_from', 'trac@localhost',
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
50 """Sender address to use in notification emails.""")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
51
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
52 smtp_replyto = Option('notification', 'smtp_replyto', 'trac@localhost',
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
53 """Reply-To address to use in notification emails.""")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
54
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
55 smtp_always_cc = Option('notification', 'smtp_always_cc', '',
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
56 """Email address(es) to always send notifications to,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
57 addresses can be see by all recipients (Cc:).""")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
58
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
59 smtp_always_bcc = Option('notification', 'smtp_always_bcc', '',
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
60 """Email address(es) to always send notifications to,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
61 addresses do not appear publicly (Bcc:). (''since 0.10'').""")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
62
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
63 smtp_default_domain = Option('notification', 'smtp_default_domain', '',
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
64 """Default host/domain to append to address that do not specify one""")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
65
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
66 mime_encoding = Option('notification', 'mime_encoding', 'base64',
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
67 """Specifies the MIME encoding scheme for emails.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
68
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
69 Valid options are 'base64' for Base64 encoding, 'qp' for
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
70 Quoted-Printable, and 'none' for no encoding. Note that the no encoding
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
71 means that non-ASCII characters in text are going to cause problems
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
72 with notifications (''since 0.10'').""")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
73
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
74 use_public_cc = BoolOption('notification', 'use_public_cc', 'false',
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
75 """Recipients can see email addresses of other CC'ed recipients.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
76
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
77 If this option is disabled (the default), recipients are put on BCC
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
78 (''since 0.10'').""")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
79
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
80 use_short_addr = BoolOption('notification', 'use_short_addr', 'false',
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
81 """Permit email address without a host/domain (i.e. username only)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
82
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
83 The SMTP server should accept those addresses, and either append
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
84 a FQDN or use local delivery (''since 0.10'').""")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
85
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
86 use_tls = BoolOption('notification', 'use_tls', 'false',
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
87 """Use SSL/TLS to send notifications (''since 0.10'').""")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
88
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
89
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
90 class Notify(object):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
91 """Generic notification class for Trac.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
92
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
93 Subclass this to implement different methods.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
94 """
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
95
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
96 def __init__(self, env):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
97 self.env = env
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
98 self.config = env.config
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
99 self.db = env.get_db_cnx()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
100
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
101 loadpaths = Chrome(self.env).get_all_templates_dirs()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
102 self.hdf = HDFWrapper(loadpaths)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
103 populate_hdf(self.hdf, env)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
104
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
105 def notify(self, resid):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
106 (torcpts, ccrcpts) = self.get_recipients(resid)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
107 self.begin_send()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
108 self.send(torcpts, ccrcpts)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
109 self.finish_send()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
110
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
111 def get_recipients(self, resid):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
112 """Return a pair of list of subscribers to the resource 'resid'.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
113
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
114 First list represents the direct recipients (To:), second list
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
115 represents the recipients in carbon copy (Cc:).
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
116 """
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
117 raise NotImplementedError
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
118
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
119 def begin_send(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
120 """Prepare to send messages.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
121
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
122 Called before sending begins.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
123 """
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
124
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
125 def send(self, torcpts, ccrcpts):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
126 """Send message to recipients."""
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
127 raise NotImplementedError
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
128
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
129 def finish_send(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
130 """Clean up after sending all messages.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
131
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
132 Called after sending all messages.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
133 """
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
134
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
135
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
136 class NotifyEmail(Notify):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
137 """Baseclass for notification by email."""
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
138
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
139 smtp_server = 'localhost'
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
140 smtp_port = 25
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
141 from_email = 'trac+tickets@localhost'
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
142 subject = ''
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
143 server = None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
144 email_map = None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
145 template_name = None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
146 addrfmt = r"[\w\d_\.\-\+=]+\@(([\w\d\-])+\.)+([\w\d]{2,4})+"
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
147 shortaddr_re = re.compile(addrfmt)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
148 longaddr_re = re.compile(r"^\s*(.*)\s+<(" + addrfmt + ")>\s*$");
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
149 nodomaddr_re = re.compile(r"[\w\d_\.\-]+")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
150 addrsep_re = re.compile(r"[;\s,]+")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
151
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
152 def __init__(self, env):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
153 Notify.__init__(self, env)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
154
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
155 self._use_tls = self.env.config.getbool('notification', 'use_tls')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
156 self._init_pref_encoding()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
157 # Get the email addresses of all known users
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
158 self.email_map = {}
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
159 for username, name, email in self.env.get_known_users(self.db):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
160 if email:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
161 self.email_map[username] = email
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
162
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
163 def _init_pref_encoding(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
164 from email.Charset import Charset, QP, BASE64
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
165 self._charset = Charset()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
166 self._charset.input_charset = 'utf-8'
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
167 pref = self.env.config.get('notification', 'mime_encoding').lower()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
168 if pref == 'base64':
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
169 self._charset.header_encoding = BASE64
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
170 self._charset.body_encoding = BASE64
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
171 self._charset.output_charset = 'utf-8'
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
172 self._charset.input_codec = 'utf-8'
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
173 self._charset.output_codec = 'utf-8'
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
174 elif pref in ['qp', 'quoted-printable']:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
175 self._charset.header_encoding = QP
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
176 self._charset.body_encoding = QP
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
177 self._charset.output_charset = 'utf-8'
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
178 self._charset.input_codec = 'utf-8'
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
179 self._charset.output_codec = 'utf-8'
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
180 elif pref == 'none':
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
181 self._charset.header_encoding = None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
182 self._charset.body_encoding = None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
183 self._charset.input_codec = None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
184 self._charset.output_charset = 'ascii'
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
185 else:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
186 raise TracError, 'Invalid email encoding setting: %s' % pref
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
187
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
188 def notify(self, resid, subject):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
189 self.subject = subject
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
190
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
191 if not self.config.getbool('notification', 'smtp_enabled'):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
192 return
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
193 self.smtp_server = self.config['notification'].get('smtp_server')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
194 self.smtp_port = self.config['notification'].getint('smtp_port')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
195 self.from_email = self.config['notification'].get('smtp_from')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
196 self.replyto_email = self.config['notification'].get('smtp_replyto')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
197 self.from_email = self.from_email or self.replyto_email
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
198 if not self.from_email and not self.replyto_email:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
199 raise TracError(Markup('Unable to send email due to identity '
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
200 'crisis.<p>Neither <b>notification.from</b> '
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
201 'nor <b>notification.reply_to</b> are '
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
202 'specified in the configuration.</p>'),
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
203 'SMTP Notification Error')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
204
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
205 # Authentication info (optional)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
206 self.user_name = self.config['notification'].get('smtp_user')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
207 self.password = self.config['notification'].get('smtp_password')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
208
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
209 Notify.notify(self, resid)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
210
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
211 def format_header(self, key, name, email=None):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
212 from email.Header import Header
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
213 maxlength = MAXHEADERLEN-(len(key)+2)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
214 # Do not sent ridiculous short headers
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
215 if maxlength < 10:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
216 raise TracError, "Header length is too short"
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
217 try:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
218 tmp = name.encode('ascii')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
219 header = Header(tmp, 'ascii', maxlinelen=maxlength)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
220 except UnicodeEncodeError:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
221 header = Header(name, self._charset, maxlinelen=maxlength)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
222 if not email:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
223 return header
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
224 else:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
225 return "\"%s\" <%s>" % (header, email)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
226
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
227 def add_headers(self, msg, headers):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
228 for h in headers:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
229 msg[h] = self.encode_header(h, headers[h])
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
230
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
231 def get_smtp_address(self, address):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
232 if not address:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
233 return None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
234 if address.find('@') == -1:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
235 if address == 'anonymous':
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
236 return None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
237 if self.email_map.has_key(address):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
238 address = self.email_map[address]
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
239 elif NotifyEmail.nodomaddr_re.match(address):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
240 if self.config.getbool('notification', 'use_short_addr'):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
241 return address
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
242 domain = self.config.get('notification', 'smtp_default_domain')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
243 if domain:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
244 address = "%s@%s" % (address, domain)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
245 else:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
246 self.env.log.info("Email address w/o domain: %s" % address)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
247 return None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
248 mo = NotifyEmail.shortaddr_re.search(address)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
249 if mo:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
250 return mo.group(0)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
251 mo = NotifyEmail.longaddr_re.search(address)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
252 if mo:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
253 return mo.group(2)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
254 self.env.log.info("Invalid email address: %s" % address)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
255 return None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
256
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
257 def encode_header(self, key, value):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
258 if isinstance(value, tuple):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
259 return self.format_header(key, value[0], value[1])
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
260 if isinstance(value, list):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
261 items = []
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
262 for v in value:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
263 items.append(self.encode_header(v))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
264 return ',\n\t'.join(items)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
265 mo = NotifyEmail.longaddr_re.match(value)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
266 if mo:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
267 return self.format_header(key, mo.group(1), mo.group(2))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
268 return self.format_header(key, value)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
269
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
270 def begin_send(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
271 self.server = smtplib.SMTP(self.smtp_server, self.smtp_port)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
272 # self.server.set_debuglevel(True)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
273 if self._use_tls:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
274 self.server.ehlo()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
275 if not self.server.esmtp_features.has_key('starttls'):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
276 raise TracError, "TLS enabled but server does not support TLS"
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
277 self.server.starttls()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
278 self.server.ehlo()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
279 if self.user_name:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
280 self.server.login(self.user_name, self.password)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
281
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
282 def send(self, torcpts, ccrcpts, mime_headers={}):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
283 from email.MIMEText import MIMEText
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
284 from email.Utils import formatdate, formataddr
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
285 body = self.hdf.render(self.template_name)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
286 projname = self.config.get('project', 'name')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
287 public_cc = self.config.getbool('notification', 'use_public_cc')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
288 headers = {}
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
289 headers['X-Mailer'] = 'Trac %s, by Edgewall Software' % __version__
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
290 headers['X-Trac-Version'] = __version__
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
291 headers['X-Trac-Project'] = projname
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
292 headers['X-URL'] = self.config.get('project', 'url')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
293 headers['Subject'] = self.subject
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
294 headers['From'] = (projname, self.from_email)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
295 headers['Sender'] = self.from_email
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
296 headers['Reply-To'] = self.replyto_email
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
297
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
298 def build_addresses(rcpts):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
299 """Format and remove invalid addresses"""
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
300 return filter(lambda x: x, \
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
301 [self.get_smtp_address(addr) for addr in rcpts])
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
302
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
303 def remove_dup(rcpts, all):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
304 """Remove duplicates"""
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
305 tmp = []
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
306 for rcpt in rcpts:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
307 if not rcpt in all:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
308 tmp.append(rcpt)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
309 all.append(rcpt)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
310 return (tmp, all)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
311
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
312 toaddrs = build_addresses(torcpts)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
313 ccaddrs = build_addresses(ccrcpts)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
314 accparam = self.config.get('notification', 'smtp_always_cc')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
315 accaddrs = accparam and \
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
316 build_addresses(accparam.replace(',', ' ').split()) or []
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
317 bccparam = self.config.get('notification', 'smtp_always_bcc')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
318 bccaddrs = bccparam and \
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
319 build_addresses(bccparam.replace(',', ' ').split()) or []
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
320
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
321 recipients = []
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
322 (toaddrs, recipients) = remove_dup(toaddrs, recipients)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
323 (ccaddrs, recipients) = remove_dup(ccaddrs, recipients)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
324 (accaddrs, recipients) = remove_dup(accaddrs, recipients)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
325 (bccaddrs, recipients) = remove_dup(bccaddrs, recipients)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
326
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
327 # if there is not valid recipient, leave immediately
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
328 if len(recipients) < 1:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
329 return
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
330
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
331 pcc = accaddrs
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
332 if public_cc:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
333 pcc += ccaddrs
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
334 if toaddrs:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
335 headers['To'] = ', '.join(toaddrs)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
336 if pcc:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
337 headers['Cc'] = ', '.join(pcc)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
338 headers['Date'] = formatdate()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
339 # sanity check
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
340 if not self._charset.body_encoding:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
341 try:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
342 dummy = body.encode('ascii')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
343 except UnicodeDecodeError:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
344 raise TracError, "Ticket contains non-Ascii chars. " \
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
345 "Please change encoding setting"
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
346 msg = MIMEText(body, 'plain')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
347 # Message class computes the wrong type from MIMEText constructor,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
348 # which does not take a Charset object as initializer. Reset the
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
349 # encoding type to force a new, valid evaluation
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
350 del msg['Content-Transfer-Encoding']
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
351 msg.set_charset(self._charset)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
352 self.add_headers(msg, headers);
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
353 self.add_headers(msg, mime_headers);
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
354 self.env.log.debug("Sending SMTP notification to %s on port %d to %s"
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
355 % (self.smtp_server, self.smtp_port, recipients))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
356 msgtext = msg.as_string()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
357 # Ensure the message complies with RFC2822: use CRLF line endings
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
358 recrlf = re.compile("\r?\n")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
359 msgtext = "\r\n".join(recrlf.split(msgtext))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
360 self.server.sendmail(msg['From'], recipients, msgtext)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
361
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
362 def finish_send(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
363 if self._use_tls:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
364 # avoid false failure detection when the server closes
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
365 # the SMTP connection with TLS enabled
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
366 import socket
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
367 try:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
368 self.server.quit()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
369 except socket.sslerror:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
370 pass
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
371 else:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
372 self.server.quit()
Copyright (C) 2012-2017 Edgewall Software