Package turbomail
[hide private]
[frames] | no frames]

Source Code for Package turbomail

  1  # encoding: utf-8 
  2   
  3  """ 
  4  Introduction 
  5  ============ 
  6   
  7          TurboMail is a TurboGears extension - meaning that it starts up and 
  8          shuts down alongside TurboGears applications you write in the same 
  9          way that visit tracking and identity do.  TurboMail uses built-in 
 10          Python modules for SMTP communication and MIME e-mail creation, but 
 11          greatly simplifies these tasks by performing the grunt-work for you. 
 12           
 13          Being multi-threaded, TurboMail allows you to enqueue messages to be 
 14          sent and then immediately continue with processing, resulting in a 
 15          much more fluid user experience.  Threads are handled intelligently 
 16          (increasing the number of threads as demand increases) and they are 
 17          automatically recycled.  There is only ever one SMTP connection per 
 18          thread. 
 19           
 20          Benchmarking 
 21          ------------ 
 22           
 23                  Throughput using the default options is sufficient for most use: 
 24                  100 messages in 45 seconds; just over 2 messages a second. Using 
 25                  a greater number of threads, 10 vs. 4, 100 messages take 30 
 26                  seconds; just over 3 messages a second.  YMMV.  Note that if a 
 27                  thread is idle, it will immediately deliver requests added to 
 28                  the queue, thus increasing the idle time will increase sparse 
 29                  performance. 
 30           
 31          TurboMail is heavily inspired by PHPMailer, a very, very handy class 
 32          for PHP 4 & 5 by Brent R. Matzelle. 
 33           
 34   
 35  Installation 
 36  ============ 
 37   
 38          Simply easy_install the package:: 
 39   
 40                  easy_install TurboMail 
 41   
 42          TurboMail installs no external scripts. 
 43   
 44  Upgrade 
 45  ======= 
 46   
 47          Upgrading also uses easy_install:: 
 48           
 49                  easy_install -U TurboMail 
 50   
 51  Configuration 
 52  ============= 
 53   
 54          TurboMail understands a large number of configuration options, all 
 55          piggy-backed from your application's configuration.  Organized into 
 56          two groups, the advanced set can be safely ignored in most 
 57          applications.  Each option is listed with its default value. 
 58           
 59          Simple Options 
 60          -------------- 
 61           
 62                   - I{mail.on} (Default: B{False}) Enable TurboMail.  B{Required.} 
 63                   - I{mail.server} (Default: B{None}) SMTP server address. 
 64                     B{Required.} 
 65                   - I{mail.username} (Default: B{None}) 
 66                   - I{mail.password} (Default: B{None}) 
 67           
 68                  Both a username and password are required to enable 
 69                  authentication. 
 70           
 71          Advanced Options 
 72          ---------------- 
 73           
 74                   - I{mail.debug} (Default: B{False}) Output all SMTP server 
 75                     communications. 
 76                   - I{mail.interval} (Default: B{10}) Polling delay between new 
 77                     thread creation, in seconds. 
 78                   - I{mail.threads} (Default: B{4}) Maximum number of concurrent 
 79                     threads. 
 80                   - I{mail.jobs} (Default: B{10}) Maximum number of job units per 
 81                     thread. 
 82                   - I{mail.timeout} (Default: B{60}) Maximum time a worker thread 
 83                     will wait for additional jobs, in seconds. 
 84                   - I{mail.tls} (Default: None) Enable or disable TLS, None will 
 85                     attempt to auto-detect TLS.  This will not always work. 
 86                   - I{mail.encoding} (Default: B{'us-ascii'}) Set the character 
 87                     set and encoding on the MIMEText parts of the message. 
 88                     Common character sets include: 
 89                      - us-ascii - I{Performs no encoding, but is 7bit only.} 
 90                      - iso-8859-1 - I{Uses quoted-printable encoding.} 
 91                      - utf-8 - I{Uses base64 encoding.} 
 92                     Due to the way Python's email package handles character sets, 
 93                     the following additional virtual character sets are provided 
 94                     by TurboMail, and will override the global defaults: 
 95                      - utf-8-qp - I{Sets utf-8 to use quoted-printable encoding.} 
 96                     Headers are not encoded.  DIY. 
 97                   - I{mail.polling} (Default: B{False}) If enabled, configures the 
 98                     thread pool to poll every I{mail.interval} seconds for new 
 99                     jobs.  This may give performance benefits to the running 
100                     application.  The default behaviour is to create new threads 
101                     as soon as work is enqueued, resulting in faster delivery. 
102                   
103                  In debug mode using a single thread with a maximum of one job 
104                  can be advantageous.  Having a single thread with a maximum of a 
105                  single job limits TurboMail to a single SMTP connection at a 
106                  time and automatically disconnects for I{each message}. 
107   
108  Basic Usage 
109  =========== 
110   
111          To use TurboMail in your TurboGears application, after adding the 
112          appropriate configuration options to your application, perform the 
113          following steps: 
114           
115           1. Import TurboMail:: 
116           
117                  import turbomail 
118           
119           2. Create a L{Message} or L{KIDMessage} object:: 
120           
121                  message = turbomail.Message(from, to, subject) 
122           
123           3. Set some content for your message:: 
124           
125                  message.plain = "Hello world!" 
126           
127           4. Enqueue your message:: 
128           
129                  turbomail.enqueue(message) 
130           
131          Your message will now have been enqueued.  It will take at most 
132          I{mail.interval} seconds for a thread to be created to deliver it. 
133          The best case scenario is if there is an idle thread waiting, in 
134          which case delivery will be immediate. 
135   
136  Advanced Usage - Logging 
137  ======================== 
138   
139          Additionally, you can configure your application to log TurboMail 
140          events differently, in a more loggable and machine parseable way. 
141          You do so by adding the following lines to the formatters section 
142          of your log.cfg:: 
143           
144                  [[[timed_message]]] 
145                  format='*(asctime)s *(message)s' 
146           
147          Add the following to the handlers section of log.cfg:: 
148           
149                  [[[mail_out]]] 
150                  class='StreamHandler' 
151                  level='INFO' 
152                  args='(sys.stdout,)' 
153                  formatter='timed_message' 
154           
155          And finally, add the following to your dev.cfg:: 
156           
157                  [[[mail]]] 
158                  level='INFO' 
159                  qualname='turbomail.dispatch' 
160                  handlers=['mail_out'] 
161                  propagate=0 
162           
163          If you wish to log mail dispatch to a file, for example in your 
164          production configuration, use this instead of the above:: 
165           
166                  [[handlers]] 
167                  [[[mail_out]]] 
168                  args="('mail.log',)" 
169                  class='StreamHandler' 
170                  level='INFO' 
171                  formatter='timed_message' 
172                   
173                  [[loggers]] 
174                  [[[mail]]] 
175                  level='INFO' 
176                  qualname='turbomail.dispatch' 
177                  handlers=['mail_out'] 
178                  propagate=0 
179           
180          The format of turbomail.dispatch INFO log entries is:: 
181           
182                  [user@]server size ("from_name") from_addr ("to_name") to_addr - subject 
183           
184          Designed for easy parsing and tracking of statistics, the log 
185          format uses the following conventions: 
186           
187           - Entries between square brackets are optional and may be omitted. 
188           - Entries between round brackets may be replaced with a dash if 
189             unavailable. 
190           - The size field is in bytes and represents the total size of the 
191             MIME-encoded message including headers, after character set 
192             conversion. 
193           - When sending to multiple recipients, the to_addr field becomes 
194             the number of recipients wrapped in round brackets.  E.g. "(3)" 
195           - The subject field extends to the EOL - quotes, dashes, and other 
196             symbols should be treated as part of the subject. 
197   
198  Changelog 
199  ========= 
200   
201          Version 1.0 
202          ----------- 
203                   - Initial release. 
204           
205          Version 1.0.1 
206          ------------- 
207                   - Minor updates to remove unneeded arguments. 
208                   - Complete source-level epydoc documentation. 
209           
210          Version 1.0.4.1 
211          --------------- 
212                   - Better auto-detection of TLS capability. 
213                   - A new configuration directive, mail.tls; True, False, or 
214                     None to auto-detect. 
215                   - Fixes a bug in KIDMessage which rendered it 
216                     non-functional. 
217                   - Changed the behavior of a worker dying from old age to spawn 
218                     a new process immediately. 
219                   - Minor fixes and updates to the documentation. 
220                   - Benchmark results in the documentation. 
221           
222          Version 1.0.4.2 
223          --------------- 
224                   - Added encoding configuration directive. 
225                   - Encoding can be passed to a Message constructor to override 
226                     the encoding on a message-by-message basis. 
227           
228          Version 1.1 
229          ----------- 
230                   - Cleaned up the log output. 
231                   - Added documentation for logging. 
232                   - KID i18n session bug fixed in TurboGears 1.0 and trunk SVN. 
233                   - Marked as stable for the Python Cheese Shop. 
234           
235          Version 2.0 
236          ----------- 
237                   - Default thread creation mechanism is on-demand, not polling. 
238                     You can change back to the (old) polling mechanism by 
239                     setting the following configuration option:: 
240                          mail.polling = True 
241                   - TemplateMessage has been renamed KIDMessage. 
242                   - Can now use 'utf-8-qp' to configure the 'utf-8' charset for 
243                     quoted-printable encoding. 
244                   - MIME-encoded message generation was re-written.  Now, simple 
245                     plain-text-only messages have almost zero overhead. 
246                     Complexity of the generated document increases with feature 
247                     use. 
248                   - It is now safe to import enqueue from TurboMail - it no 
249                     longer polymorphs after TurboGears start-up and shutdown. 
250                   - Enhanced logging output - see above. 
251                   - Better tracking of when to rebuild the MIME message by using 
252                     a dirty flag. 
253                   - Many, many additional headers.  Look at the documentation for 
254                     the message class for more information. 
255                   - Multiple recipients. 
256                   
257                  There is, however, an outstanding bug in KIDMessage.  When 
258                  generating the plain-text alternative KID seems to default 
259                  to ascii encoding, which bombs out if you use any extended 
260                  characters in the template, or variables passed to the template. 
261                   
262          Version 2.0.1 
263          ------------- 
264                   - Applied patch submitted by Jason Chu to allow overriding of 
265                     the Sender and Return-Path headers. 
266                   - Applied patch submitted by Jason Chu to correct the MIME 
267                     type of dual text & html messages with attachments. 
268   
269          Version 2.0.2 
270          ------------- 
271                   - Added a generic ControllerMessage which uses the output of 
272                     any function or method that returns HTML. 
273                   - Changed the behaviour of the attach and embed methods to 
274                     pull content from an existing file-like object or open an 
275                     on-disk file. 
276                   - Corrected a conditional testing for the presense of 
277                     smptfrom as a message property.  Thanks James! 
278                   
279          Version 2.0.3 
280          ------------- 
281                   - The plain and rich properties of the Message class can now 
282                     be callables, executed at delivery-time. 
283                   - Removed ControllerMessage in favor of using the above. 
284                   - Deprecated use of KIDMessage in favor of the above. 
285   
286  @var _queue: After TurboGears startup within an application which has 
287              enabled TurboMail, I{queue} is an instance of a MailPool 
288              object. 
289   
290  """ 
291   
292  from turbomail.release import \ 
293                  version as __version__, \ 
294                  author as __author__, \ 
295                  email as __email__, \ 
296                  license as __license__, \ 
297                  copyright as __copyright__ 
298   
299  import logging 
300  log = logging.getLogger("turbomail") 
301   
302  from turbomail.startup import start_extension, shutdown_extension 
303  from turbomail.exceptions import * 
304  from turbomail.message import Message, KIDMessage 
305   
306   
307  __all__ = ['MailException', 'MailNotEnabledException', 'MailConfigurationException', 'Message', 'KIDMessage', 'enqueue', 'dispatch', 'exceptions', 'message', 'pool', 'startup'] 
308   
309   
310  _queue = None 
311   
312 -def enqueue(work):
313 """Enqueue a message in the message thread-pool queue.""" 314 315 if _queue is None: 316 raise MailNotEnabledException 317 318 else: 319 _queue.enqueue(work)
320