summaryrefslogtreecommitdiff
path: root/vendor/swiftmailer/swiftmailer/doc/sending.rst
blob: f340404cad48a9fd1b44601a8973001ede23f072 (plain)
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
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
Sending Messages
================

Quick Reference for Sending a Message
-------------------------------------

Sending a message is very straightforward. You create a Transport, use it to
create the Mailer, then you use the Mailer to send the message.

To send a Message:

* Create a Transport from one of the provided Transports --
  ``Swift_SmtpTransport``, ``Swift_SendmailTransport``
  or one of the aggregate Transports.

* Create an instance of the ``Swift_Mailer`` class, using the Transport as
  it's constructor parameter.

* Create a Message.

* Send the message via the ``send()`` method on the Mailer object.

.. caution::

    The ``Swift_SmtpTransport`` and ``Swift_SendmailTransport`` transports use
    ``proc_*`` PHP functions, which might not be available on your PHP
    installation. You can easily check if that's the case by running the
    following PHP script: ``<?php echo function_exists('proc_open') ? "Yep,
    that will work" : "Sorry, that won't work";``

When using ``send()`` the message will be sent just like it would be sent if you
used your mail client. An integer is returned which includes the number of
successful recipients. If none of the recipients could be sent to then zero will
be returned, which equates to a boolean ``false``. If you set two ``To:``
recipients and three ``Bcc:`` recipients in the message and all of the
recipients are delivered to successfully then the value 5 will be returned.

.. code-block:: php

    require_once 'lib/swift_required.php';

    // Create the Transport
    $transport = Swift_SmtpTransport::newInstance('smtp.example.org', 25)
      ->setUsername('your username')
      ->setPassword('your password')
      ;

    /*
    You could alternatively use a different transport such as Sendmail:

    // Sendmail
    $transport = Swift_SendmailTransport::newInstance('/usr/sbin/sendmail -bs');
    */

    // Create the Mailer using your created Transport
    $mailer = Swift_Mailer::newInstance($transport);

    // Create a message
    $message = Swift_Message::newInstance('Wonderful Subject')
      ->setFrom(array('john@doe.com' => 'John Doe'))
      ->setTo(array('receiver@domain.org', 'other@domain.org' => 'A name'))
      ->setBody('Here is the message itself')
      ;

    // Send the message
    $result = $mailer->send($message);

Transport Types
~~~~~~~~~~~~~~~

A Transport is the component which actually does the sending. You need to
provide a Transport object to the Mailer class and there are several possible
options.

Typically you will not need to know how a Transport works under-the-surface,
you will only need to know how to create an instance of one, and which one to
use for your environment.

The SMTP Transport
..................

The SMTP Transport sends messages over the (standardized) Simple Message
Transfer Protocol.  It can deal with encryption and authentication.

The SMTP Transport, ``Swift_SmtpTransport`` is without doubt the most commonly
used Transport because it will work on 99% of web servers (I just made that
number up, but you get the idea). All the server needs is the ability to
connect to a remote (or even local) SMTP server on the correct port number
(usually 25).

SMTP servers often require users to authenticate with a username and password
before any mail can be sent to other domains. This is easily achieved using
Swift Mailer with the SMTP Transport.

SMTP is a protocol -- in other words it's a "way" of communicating a job
to be done (i.e. sending a message). The SMTP protocol is the fundamental
basis on which messages are delivered all over the internet 7 days a week, 365
days a year. For this reason it's the most "direct" method of sending messages
you can use and it's the one that will give you the most power and feedback
(such as delivery failures) when using Swift Mailer.

Because SMTP is generally run as a remote service (i.e. you connect to it over
the network/internet) it's extremely portable from server-to-server. You can
easily store the SMTP server address and port number in a configuration file
within your application and adjust the settings accordingly if the code is
moved or if the SMTP server is changed.

Some SMTP servers -- Google for example -- use encryption for security reasons.
Swift Mailer supports using both SSL and TLS encryption settings.

Using the SMTP Transport
^^^^^^^^^^^^^^^^^^^^^^^^

The SMTP Transport is easy to use. Most configuration options can be set with
the constructor.

To use the SMTP Transport you need to know which SMTP server your code needs
to connect to. Ask your web host if you're not sure. Lots of people ask me who
to connect to -- I really can't answer that since it's a setting that's
extremely specific to your hosting environment.

To use the SMTP Transport:

* Call ``Swift_SmtpTransport::newInstance()`` with the SMTP server name and
  optionally with a port number (defaults to 25).

* Use the returned object to create the Mailer.

A connection to the SMTP server will be established upon the first call to
``send()``.

.. code-block:: php

    require_once 'lib/swift_required.php';

    // Create the Transport
    $transport = Swift_SmtpTransport::newInstance('smtp.example.org', 25);

    // Create the Mailer using your created Transport
    $mailer = Swift_Mailer::newInstance($transport);

    /*
    It's also possible to use multiple method calls

    $transport = Swift_SmtpTransport::newInstance()
      ->setHost('smtp.example.org')
      ->setPort(25)
      ;
    */

Encrypted SMTP
^^^^^^^^^^^^^^

You can use SSL or TLS encryption with the SMTP Transport by specifying it as
a parameter or with a method call.

To use encryption with the SMTP Transport:

* Pass the encryption setting as a third parameter to
  ``Swift_SmtpTransport::newInstance()``; or

* Call the ``setEncryption()`` method on the Transport.

A connection to the SMTP server will be established upon the first call to
``send()``. The connection will be initiated with the correct encryption
settings.

.. note::

    For SSL or TLS encryption to work your PHP installation must have
    appropriate OpenSSL transports wrappers. You can check if "tls" and/or
    "ssl" are present in your PHP installation by using the PHP function
    ``stream_get_transports()``

    .. code-block:: php

        require_once 'lib/swift_required.php';

        // Create the Transport
        $transport = Swift_SmtpTransport::newInstance('smtp.example.org', 587, 'ssl');

        // Create the Mailer using your created Transport
        $mailer = Swift_Mailer::newInstance($transport);

        /*
        It's also possible to use multiple method calls

        $transport = Swift_SmtpTransport::newInstance()
          ->setHost('smtp.example.org')
          ->setPort(587)
          ->setEncryption('ssl')
          ;
        */

SMTP with a Username and Password
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Some servers require authentication. You can provide a username and password
with ``setUsername()`` and ``setPassword()`` methods.

To use a username and password with the SMTP Transport:

* Create the Transport with ``Swift_SmtpTransport::newInstance()``.

* Call the ``setUsername()`` and ``setPassword()`` methods on the Transport.

Your username and password will be used to authenticate upon first connect
when ``send()`` are first used on the Mailer.

If authentication fails, an Exception of type ``Swift_TransportException`` will
be thrown.

.. note::

    If you need to know early whether or not authentication has failed and an
    Exception is going to be thrown, call the ``start()`` method on the
    created Transport.

    .. code-block:: php

        require_once 'lib/swift_required.php';

        // Create the Transport the call setUsername() and setPassword()
        $transport = Swift_SmtpTransport::newInstance('smtp.example.org', 25)
          ->setUsername('username')
          ->setPassword('password')
          ;

        // Create the Mailer using your created Transport
        $mailer = Swift_Mailer::newInstance($transport);

The Sendmail Transport
......................

The Sendmail Transport sends messages by communicating with a locally
installed MTA -- such as ``sendmail``.

The Sendmail Transport, ``Swift_SendmailTransport`` does not directly connect to
any remote services. It is designed for Linux servers that have ``sendmail``
installed. The Transport starts a local ``sendmail`` process and sends messages
to it. Usually the ``sendmail`` process will respond quickly as it spools your
messages to disk before sending them.

The Transport is named the Sendmail Transport for historical reasons
(``sendmail`` was the "standard" UNIX tool for sending e-mail for years). It
will send messages using other transfer agents such as Exim or Postfix despite
its name, provided they have the relevant sendmail wrappers so that they can be
started with the correct command-line flags.

It's a common misconception that because the Sendmail Transport returns a
result very quickly it must therefore deliver messages to recipients quickly
-- this is not true. It's not slow by any means, but it's certainly not
faster than SMTP when it comes to getting messages to the intended recipients.
This is because sendmail itself sends the messages over SMTP once they have
been quickly spooled to disk.

The Sendmail Transport has the potential to be just as smart of the SMTP
Transport when it comes to notifying Swift Mailer about which recipients were
rejected, but in reality the majority of locally installed ``sendmail``
instances are not configured well enough to provide any useful feedback. As such
Swift Mailer may report successful deliveries where they did in fact fail before
they even left your server.

You can run the Sendmail Transport in two different modes specified by command
line flags:

* "``-bs``" runs in SMTP mode so theoretically it will act like the SMTP
  Transport

* "``-t``" runs in piped mode with no feedback, but theoretically faster,
  though not advised

You can think of the Sendmail Transport as a sort of asynchronous SMTP Transport
-- though if you have problems with delivery failures you should try using the
SMTP Transport instead. Swift Mailer isn't doing the work here, it's simply
passing the work to somebody else (i.e. ``sendmail``).

Using the Sendmail Transport
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

To use the Sendmail Transport you simply need to call
``Swift_SendmailTransport::newInstance()`` with the command as a parameter.

To use the Sendmail Transport you need to know where ``sendmail`` or another MTA
exists on the server. Swift Mailer uses a default value of
``/usr/sbin/sendmail``, which should work on most systems.

You specify the entire command as a parameter (i.e. including the command line
flags). Swift Mailer supports operational modes of "``-bs``" (default) and
"``-t``".

.. note::

    If you run sendmail in "``-t``" mode you will get no feedback as to whether
    or not sending has succeeded. Use "``-bs``" unless you have a reason not to.

To use the Sendmail Transport:

* Call ``Swift_SendmailTransport::newInstance()`` with the command, including
  the correct command line flags. The default is to use ``/usr/sbin/sendmail
  -bs`` if this is not specified.

* Use the returned object to create the Mailer.

A sendmail process will be started upon the first call to ``send()``. If the
process cannot be started successfully an Exception of type
``Swift_TransportException`` will be thrown.

.. code-block:: php

    require_once 'lib/swift_required.php';

    // Create the Transport
    $transport = Swift_SendmailTransport::newInstance('/usr/sbin/exim -bs');

    // Create the Mailer using your created Transport
    $mailer = Swift_Mailer::newInstance($transport);

The Mail Transport
..................

The Mail Transport sends messages by delegating to PHP's internal
``mail()`` function.

In my experience -- and others' -- the ``mail()`` function is not particularly
predictable, or helpful.

Quite notably, the ``mail()`` function behaves entirely differently between
Linux and Windows servers. On linux it uses ``sendmail``, but on Windows it uses
SMTP.

In order for the ``mail()`` function to even work at all ``php.ini`` needs to be
configured correctly, specifying the location of sendmail or of an SMTP server.

The problem with ``mail()`` is that it "tries" to simplify things to the point
that it actually makes things more complex due to poor interface design. The
developers of Swift Mailer have gone to a lot of effort to make the Mail
Transport work with a reasonable degree of consistency.

Serious drawbacks when using this Transport are:

* Unpredictable message headers

* Lack of feedback regarding delivery failures

* Lack of support for several plugins that require real-time delivery feedback

It's a last resort, and we say that with a passion!

Available Methods for Sending Messages
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The Mailer class offers two methods for sending Messages -- ``send()``.
Each behaves in a slightly different way.

When a message is sent in Swift Mailer, the Mailer class communicates with
whichever Transport class you have chosen to use.

Each recipient in the message should either be accepted or rejected by the
Transport. For example, if the domain name on the email address is not
reachable the SMTP Transport may reject the address because it cannot process
it. Whichever method you use -- ``send()`` -- Swift Mailer will return
an integer indicating the number of accepted recipients.

.. note::

    It's possible to find out which recipients were rejected -- we'll cover that
    later in this chapter.

Using the ``send()`` Method
...........................

The ``send()`` method of the ``Swift_Mailer`` class sends a message using
exactly the same logic as your Desktop mail client would use. Just pass it a
Message and get a result.

To send a Message with ``send()``:

* Create a Transport from one of the provided Transports --
  ``Swift_SmtpTransport``, ``Swift_SendmailTransport``,
  or one of the aggregate Transports.

* Create an instance of the ``Swift_Mailer`` class, using the Transport as
  it's constructor parameter.

* Create a Message.

* Send the message via the ``send()`` method on the Mailer object.

The message will be sent just like it would be sent if you used your mail
client. An integer is returned which includes the number of successful
recipients. If none of the recipients could be sent to then zero will be
returned, which equates to a boolean ``false``. If you set two
``To:`` recipients and three ``Bcc:`` recipients in the message and all of the
recipients are delivered to successfully then the value 5 will be returned.

.. code-block:: php

    require_once 'lib/swift_required.php';

    // Create the Transport
    $transport = Swift_SmtpTransport::newInstance('localhost', 25);

    // Create the Mailer using your created Transport
    $mailer = Swift_Mailer::newInstance($transport);

    // Create a message
    $message = Swift_Message::newInstance('Wonderful Subject')
      ->setFrom(array('john@doe.com' => 'John Doe'))
      ->setTo(array('receiver@domain.org', 'other@domain.org' => 'A name'))
      ->setBody('Here is the message itself')
      ;

    // Send the message
    $numSent = $mailer->send($message);

    printf("Sent %d messages\n", $numSent);

    /* Note that often that only the boolean equivalent of the
       return value is of concern (zero indicates FALSE)

    if ($mailer->send($message))
    {
      echo "Sent\n";
    }
    else
    {
      echo "Failed\n";
    }

    */

Sending Emails in Batch
.......................

If you want to send a separate message to each recipient so that only their
own address shows up in the ``To:`` field, follow the following recipe:

* Create a Transport from one of the provided Transports --
  ``Swift_SmtpTransport``, ``Swift_SendmailTransport``,
  or one of the aggregate Transports.

* Create an instance of the ``Swift_Mailer`` class, using the Transport as
  it's constructor parameter.

* Create a Message.

* Iterate over the recipients and send message via the ``send()`` method on
  the Mailer object.

Each recipient of the messages receives a different copy with only their own
email address on the ``To:`` field.

Make sure to add only valid email addresses as recipients. If you try to add an
invalid email address with ``setTo()``, ``setCc()`` or ``setBcc()``, Swift
Mailer will throw a ``Swift_RfcComplianceException``.

If you add recipients automatically based on a data source that may contain
invalid email addresses, you can prevent possible exceptions by validating the
addresses using ``Swift_Validate::email($email)`` and only adding addresses
that validate. Another way would be to wrap your ``setTo()``, ``setCc()`` and
``setBcc()`` calls in a try-catch block and handle the
``Swift_RfcComplianceException`` in the catch block.

Handling invalid addresses properly is especially important when sending emails
in large batches since a single invalid address might cause an unhandled
exception and stop the execution or your script early.

.. note::

    In the following example, two emails are sent. One to each of
    ``receiver@domain.org`` and ``other@domain.org``. These recipients will
    not be aware of each other.

    .. code-block:: php

        require_once 'lib/swift_required.php';

        // Create the Transport
        $transport = Swift_SmtpTransport::newInstance('localhost', 25);

        // Create the Mailer using your created Transport
        $mailer = Swift_Mailer::newInstance($transport);

        // Create a message
        $message = Swift_Message::newInstance('Wonderful Subject')
          ->setFrom(array('john@doe.com' => 'John Doe'))
          ->setBody('Here is the message itself')
          ;

        // Send the message
        $failedRecipients = array();
        $numSent = 0;
        $to = array('receiver@domain.org', 'other@domain.org' => 'A name');

        foreach ($to as $address => $name)
        {
          if (is_int($address)) {
            $message->setTo($name);
          } else {
            $message->setTo(array($address => $name));
          }

          $numSent += $mailer->send($message, $failedRecipients);
        }

        printf("Sent %d messages\n", $numSent);

Finding out Rejected Addresses
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

It's possible to get a list of addresses that were rejected by the Transport
by using a by-reference parameter to ``send()``.

As Swift Mailer attempts to send the message to each address given to it, if a
recipient is rejected it will be added to the array. You can pass an existing
array, otherwise one will be created by-reference.

Collecting the list of recipients that were rejected can be useful in
circumstances where you need to "prune" a mailing list for example when some
addresses cannot be delivered to.

Getting Failures By-reference
.............................

Collecting delivery failures by-reference with the ``send()`` method is as
simple as passing a variable name to the method call.

To get failed recipients by-reference:

* Pass a by-reference variable name to the ``send()`` method of the Mailer
  class.

If the Transport rejects any of the recipients, the culprit addresses will be
added to the array provided by-reference.

.. note::

    If the variable name does not yet exist, it will be initialized as an
    empty array and then failures will be added to that array. If the variable
    already exists it will be type-cast to an array and failures will be added
    to it.

    .. code-block:: php

        $mailer = Swift_Mailer::newInstance( ... );

        $message = Swift_Message::newInstance( ... )
          ->setFrom( ... )
          ->setTo(array(
            'receiver@bad-domain.org' => 'Receiver Name',
            'other@domain.org' => 'A name',
            'other-receiver@bad-domain.org' => 'Other Name'
          ))
          ->setBody( ... )
          ;

        // Pass a variable name to the send() method
        if (!$mailer->send($message, $failures))
        {
          echo "Failures:";
          print_r($failures);
        }

        /*
        Failures:
        Array (
          0 => receiver@bad-domain.org,
          1 => other-receiver@bad-domain.org
        )
        */