| 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 messags 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} (Defalut: 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} (Defaut: 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 parsable 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 | | """ |
| | 8 | TurboMail is heavily inspired by PHPMailer, a very, very handy class |
| | 9 | for PHP 4 & 5 by Brent R. Matzelle.""" |