|
1 Plugins |
|
2 ======= |
|
3 |
|
4 Plugins are provided with Swift Mailer and can be used to extend the behavior |
|
5 of the library in ways that simple class inheritance would be more complex. |
|
6 |
|
7 AntiFlood Plugin |
|
8 ---------------- |
|
9 |
|
10 Many SMTP servers have limits on the number of messages that may be sent |
|
11 during any single SMTP connection. The AntiFlood plugin provides a way to stay |
|
12 within this limit while still managing a large number of emails. |
|
13 |
|
14 A typical limit for a single connection is 100 emails. If the server you |
|
15 connect to imposes such a limit, it expects you to disconnect after that |
|
16 number of emails has been sent. You could manage this manually within a loop, |
|
17 but the AntiFlood plugin provides the necessary wrapper code so that you don't |
|
18 need to worry about this logic. |
|
19 |
|
20 Regardless of limits imposed by the server, it's usually a good idea to be |
|
21 conservative with the resources of the SMTP server. Sending will become |
|
22 sluggish if the server is being over-used so using the AntiFlood plugin will |
|
23 not be a bad idea even if no limits exist. |
|
24 |
|
25 The AntiFlood plugin's logic is basically to disconnect and the immediately |
|
26 re-connect with the SMTP server every X number of emails sent, where X is a |
|
27 number you specify to the plugin. |
|
28 |
|
29 You can also specify a time period in seconds that Swift Mailer should pause |
|
30 for between the disconnect/re-connect process. It's a good idea to pause for a |
|
31 short time (say 30 seconds every 100 emails) simply to give the SMTP server a |
|
32 chance to process its queue and recover some resources. |
|
33 |
|
34 Using the AntiFlood Plugin |
|
35 ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
36 |
|
37 The AntiFlood Plugin -- like all plugins -- is added with the Mailer |
|
38 class' ``registerPlugin()`` method. It takes two constructor |
|
39 parameters: the number of emails to pause after, and optionally the number of |
|
40 seconds to pause for. |
|
41 |
|
42 To use the AntiFlood plugin: |
|
43 |
|
44 * Create an instance of the Mailer using any Transport you choose. |
|
45 |
|
46 * Create an instance of the ``Swift_Plugins_AntiFloodPlugin`` class, passing |
|
47 in one or two constructor parameters. |
|
48 |
|
49 * Register the plugin using the Mailer's ``registerPlugin()`` method. |
|
50 |
|
51 * Continue using Swift Mailer to send messages as normal. |
|
52 |
|
53 When Swift Mailer sends messages it will count the number of messages that |
|
54 have been sent since the last re-connect. Once the number hits your specified |
|
55 threshold it will disconnect and re-connect, optionally pausing for a |
|
56 specified amount of time. |
|
57 |
|
58 .. code-block:: php |
|
59 |
|
60 require_once 'lib/swift_required.php'; |
|
61 |
|
62 //Create the Mailer using any Transport |
|
63 $mailer = Swift_Mailer::newInstance( |
|
64 Swift_SmtpTransport::newInstance('smtp.example.org', 25) |
|
65 ); |
|
66 |
|
67 //Use AntiFlood to re-connect after 100 emails |
|
68 $mailer->registerPlugin(new Swift_Plugins_AntiFloodPlugin(100)); |
|
69 |
|
70 //Or specify a time in seconds to pause for (30 secs) |
|
71 $mailer->registerPlugin(new Swift_Plugins_AntiFloodPlugin(100, 30)); |
|
72 |
|
73 //Continue sending as normal |
|
74 for ($lotsOfRecipients as $recipient) { |
|
75 ... |
|
76 |
|
77 $mailer->send( ... ); |
|
78 } |
|
79 |
|
80 Throttler Plugin |
|
81 ---------------- |
|
82 |
|
83 If your SMTP server has restrictions in place to limit the rate at which you |
|
84 send emails, then your code will need to be aware of this rate-limiting. The |
|
85 Throttler plugin makes Swift Mailer run at a rate-limited speed. |
|
86 |
|
87 Many shared hosts don't open their SMTP servers as a free-for-all. Usually |
|
88 they have policies in place (probably to discourage spammers) that only allow |
|
89 you to send a fixed number of emails per-hour/day. |
|
90 |
|
91 The Throttler plugin supports two modes of rate-limiting and with each, you |
|
92 will need to do that math to figure out the values you want. The plugin can |
|
93 limit based on the number of emails per minute, or the number of |
|
94 bytes-transferred per-minute. |
|
95 |
|
96 Using the Throttler Plugin |
|
97 ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
98 |
|
99 The Throttler Plugin -- like all plugins -- is added with the Mailer |
|
100 class' ``registerPlugin()`` method. It has two required |
|
101 constructor parameters that tell it how to do its rate-limiting. |
|
102 |
|
103 To use the Throttler plugin: |
|
104 |
|
105 * Create an instance of the Mailer using any Transport you choose. |
|
106 |
|
107 * Create an instance of the ``Swift_Plugins_ThrottlerPlugin`` class, passing |
|
108 the number of emails, or bytes you wish to limit by, along with the mode |
|
109 you're using. |
|
110 |
|
111 * Register the plugin using the Mailer's ``registerPlugin()`` method. |
|
112 |
|
113 * Continue using Swift Mailer to send messages as normal. |
|
114 |
|
115 When Swift Mailer sends messages it will keep track of the rate at which |
|
116 sending messages is occuring. If it realises that sending is happening too |
|
117 fast, it will cause your program to ``sleep()`` for enough time |
|
118 to average out the rate. |
|
119 |
|
120 .. code-block:: php |
|
121 |
|
122 require_once 'lib/swift_required.php'; |
|
123 |
|
124 //Create the Mailer using any Transport |
|
125 $mailer = Swift_Mailer::newInstance( |
|
126 Swift_SmtpTransport::newInstance('smtp.example.org', 25) |
|
127 ); |
|
128 |
|
129 //Rate limit to 100 emails per-minute |
|
130 $mailer->registerPlugin(new Swift_Plugins_ThrottlerPlugin( |
|
131 100, Swift_Plugins_ThrottlerPlugin::MESSAGES_PER_MINUTE |
|
132 )); |
|
133 |
|
134 //Rate limit to 10MB per-minute |
|
135 $mailer->registerPlugin(new Swift_Plugins_ThrottlerPlugin( |
|
136 1024 * 1024 * 10, Swift_Plugins_ThrottlerPlugin::BYTES_PER_MINUTE |
|
137 )); |
|
138 |
|
139 //Continue sending as normal |
|
140 for ($lotsOfRecipients as $recipient) { |
|
141 ... |
|
142 |
|
143 $mailer->send( ... ); |
|
144 } |
|
145 |
|
146 Logger Plugin |
|
147 ~~~~~~~~~~~~~ |
|
148 |
|
149 The Logger plugins helps with debugging during the process of sending. It can |
|
150 help to identify why an SMTP server is rejecting addresses, or any other |
|
151 hard-to-find problems that may arise. |
|
152 |
|
153 The Logger plugin comes in two parts. There's the plugin itself, along with |
|
154 one of a number of possible Loggers that you may choose to use. For example, |
|
155 the logger may output messages directly in realtime, or it may capture |
|
156 messages in an array. |
|
157 |
|
158 One other notable feature is the way in which the Logger plugin changes |
|
159 Exception messages. If Exceptions are being thrown but the error message does |
|
160 not provide conclusive information as to the source of the problem (such as an |
|
161 ambiguous SMTP error) the Logger plugin includes the entire SMTP transcript in |
|
162 the error message so that debugging becomes a simpler task. |
|
163 |
|
164 There are a few available Loggers included with Swift Mailer, but writing your |
|
165 own implementation is incredibly simple and is achieved by creating a short |
|
166 class that implements the ``Swift_Plugins_Logger`` interface. |
|
167 |
|
168 * ``Swift_Plugins_Loggers_ArrayLogger``: Keeps a collection of log messages |
|
169 inside an array. The array content can be cleared or dumped out to the |
|
170 screen. |
|
171 |
|
172 * ``Swift_Plugins_Loggers_EchoLogger``: Prints output to the screen in |
|
173 realtime. Handy for very rudimentary debug output. |
|
174 |
|
175 Using the Logger Plugin |
|
176 ....................... |
|
177 |
|
178 The Logger Plugin -- like all plugins -- is added with the Mailer |
|
179 class' ``registerPlugin()`` method. It accepts an instance of |
|
180 ``Swift_Plugins_Logger`` in its constructor. |
|
181 |
|
182 To use the Logger plugin: |
|
183 |
|
184 * Create an instance of the Mailer using any Transport you choose. |
|
185 |
|
186 * Create an instance of the a Logger implementation of |
|
187 ``Swift_Plugins_Logger``. |
|
188 |
|
189 * Create an instance of the ``Swift_Plugins_LoggerPlugin`` class, passing the |
|
190 created Logger instance to its constructor. |
|
191 |
|
192 * Register the plugin using the Mailer's ``registerPlugin()`` method. |
|
193 |
|
194 * Continue using Swift Mailer to send messages as normal. |
|
195 |
|
196 * Dump the contents of the log with the logger's ``dump()`` method. |
|
197 |
|
198 When Swift Mailer sends messages it will keep a log of all the interactions |
|
199 with the underlying Transport being used. Depending upon the Logger that has |
|
200 been used the behaviour will differ, but all implementations offer a way to |
|
201 get the contents of the log. |
|
202 |
|
203 .. code-block:: php |
|
204 |
|
205 require_once 'lib/swift_required.php'; |
|
206 |
|
207 //Create the Mailer using any Transport |
|
208 $mailer = Swift_Mailer::newInstance( |
|
209 Swift_SmtpTransport::newInstance('smtp.example.org', 25) |
|
210 ); |
|
211 |
|
212 //To use the ArrayLogger |
|
213 $logger = new Swift_Plugins_Loggers_ArrayLogger(); |
|
214 $mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($logger)); |
|
215 |
|
216 //Or to use the Echo Logger |
|
217 $logger = new Swift_Plugins_Loggers_EchoLogger(); |
|
218 $mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($logger)); |
|
219 |
|
220 //Continue sending as normal |
|
221 for ($lotsOfRecipients as $recipient) { |
|
222 ... |
|
223 |
|
224 $mailer->send( ... ); |
|
225 } |
|
226 |
|
227 // Dump the log contents |
|
228 // NOTE: The EchoLogger dumps in realtime so dump() does nothing for it |
|
229 echo $logger->dump(); |
|
230 |
|
231 Decorator Plugin |
|
232 ~~~~~~~~~~~~~~~~ |
|
233 |
|
234 Often there's a need to send the same message to multiple recipients, but with |
|
235 tiny variations such as the recipient's name being used inside the message |
|
236 body. The Decorator plugin aims to provide a solution for allowing these small |
|
237 differences. |
|
238 |
|
239 The decorator plugin works by intercepting the sending process of Swift |
|
240 Mailer, reading the email address in the To: field and then looking up a set |
|
241 of replacements for a template. |
|
242 |
|
243 While the use of this plugin is simple, it is probably the most commonly |
|
244 misunderstood plugin due to the way in which it works. The typical mistake |
|
245 users make is to try registering the plugin multiple times (once for each |
|
246 recipient) -- inside a loop for example. This is incorrect. |
|
247 |
|
248 The Decorator plugin should be registered just once, but containing the list |
|
249 of all recipients prior to sending. It will use this list of recipients to |
|
250 find the required replacements during sending. |
|
251 |
|
252 Using the Decorator Plugin |
|
253 .......................... |
|
254 |
|
255 To use the Decorator plugin, simply create an associative array of |
|
256 replacements based on email addresses and then use the mailer's |
|
257 ``registerPlugin()`` method to add the plugin. |
|
258 |
|
259 First create an associative array of replacements based on the email addresses |
|
260 you'll be sending the message to. |
|
261 |
|
262 .. note:: |
|
263 |
|
264 The replacements array becomes a 2-dimensional array whose keys are the |
|
265 email addresses and whose values are an associative array of replacements |
|
266 for that email address. The curly braces used in this example can be any |
|
267 type of syntax you choose, provided they match the placeholders in your |
|
268 email template. |
|
269 |
|
270 .. code-block:: php |
|
271 |
|
272 $replacements = array(); |
|
273 foreach ($users as $user) { |
|
274 $replacements[$user['email']] = array( |
|
275 '{username}'=>$user['username'], |
|
276 '{password}'=>$user['password'] |
|
277 ); |
|
278 } |
|
279 |
|
280 Now create an instance of the Decorator plugin using this array of |
|
281 replacements and then register it with the Mailer. Do this only once! |
|
282 |
|
283 .. code-block:: php |
|
284 |
|
285 $decorator = new Swift_Plugins_DecoratorPlugin($replacements); |
|
286 |
|
287 $mailer->registerPlugin($decorator); |
|
288 |
|
289 When you create your message, replace elements in the body (and/or the subject |
|
290 line) with your placeholders. |
|
291 |
|
292 .. code-block:: php |
|
293 |
|
294 $message = Swift_Message::newInstance() |
|
295 ->setSubject('Important notice for {username}') |
|
296 ->setBody( |
|
297 "Hello {username}, we have reset your password to {password}\n" . |
|
298 "Please log in and change it at your earliest convenience." |
|
299 ) |
|
300 ; |
|
301 |
|
302 foreach ($users as $user) { |
|
303 $message->addTo($user['email']); |
|
304 } |
|
305 |
|
306 When you send this message to each of your recipients listed in your |
|
307 ``$replacements`` array they will receive a message customized |
|
308 for just themselves. For example, the message used above when received may |
|
309 appear like this to one user: |
|
310 |
|
311 .. code-block:: text |
|
312 |
|
313 Subject: Important notice for smilingsunshine2009 |
|
314 |
|
315 Hello smilingsunshine2009, we have reset your password to rainyDays |
|
316 Please log in and change it at your earliest convenience. |
|
317 |
|
318 While another use may receive the message as: |
|
319 |
|
320 .. code-block:: text |
|
321 |
|
322 Subject: Important notice for billy-bo-bob |
|
323 |
|
324 Hello billy-bo-bob, we have reset your password to dancingOctopus |
|
325 Please log in and change it at your earliest convenience. |
|
326 |
|
327 While the decorator plugin provides a means to solve this problem, there are |
|
328 various ways you could tackle this problem without the need for a plugin. |
|
329 We're trying to come up with a better way ourselves and while we have several |
|
330 (obvious) ideas we don't quite have the perfect solution to go ahead and |
|
331 implement it. Watch this space. |
|
332 |
|
333 Providing Your Own Replacements Lookup for the Decorator |
|
334 ........................................................ |
|
335 |
|
336 Filling an array with replacements may not be the best solution for providing |
|
337 replacement information to the decorator. If you have a more elegant algorithm |
|
338 that performs replacement lookups on-the-fly you may provide your own |
|
339 implementation. |
|
340 |
|
341 Providing your own replacements lookup implementation for the Decorator is |
|
342 simply a matter of passing an instance of |
|
343 ``Swift_Plugins_Decorator_Replacements`` to the decorator |
|
344 plugin's constructor, rather than passing in an array. |
|
345 |
|
346 The Replacements interface is very simple to implement since it has just one |
|
347 method: ``getReplacementsFor($address)``. |
|
348 |
|
349 Imagine you want to look up replacements from a database on-the-fly, you might |
|
350 provide an implementation that does this. You need to create a small class. |
|
351 |
|
352 .. code-block:: php |
|
353 |
|
354 class DbReplacements implements Swift_Plugins_Decorator_Replacements { |
|
355 public function getReplacementsFor($address) { |
|
356 $sql = sprintf( |
|
357 "SELECT * FROM user WHERE email = '%s'", |
|
358 mysql_real_escape_string($address) |
|
359 ); |
|
360 |
|
361 $result = mysql_query($sql); |
|
362 |
|
363 if ($row = mysql_fetch_assoc($result)) { |
|
364 return array( |
|
365 '{username}'=>$row['username'], |
|
366 '{password}'=>$row['password'] |
|
367 ); |
|
368 } |
|
369 } |
|
370 } |
|
371 |
|
372 Now all you need to do is pass an instance of your class into the Decorator |
|
373 plugin's constructor instead of passing an array. |
|
374 |
|
375 .. code-block:: php |
|
376 |
|
377 $decorator = new Swift_Plugins_DecoratorPlugin(new DbReplacements()); |
|
378 |
|
379 $mailer->registerPlugin($decorator); |
|
380 |
|
381 For each message sent, the plugin will call your class' |
|
382 ``getReplacementsFor()`` method to find the array of replacements |
|
383 it needs. |
|
384 |
|
385 .. note:: |
|
386 |
|
387 If your lookup algorithm is case sensitive, you should transform the |
|
388 ``$address`` argument as appropriate -- for example by passing it |
|
389 through ``strtolower()``. |