Как спулить электронные письма

Поведение почтовой программы Symfony по умолчанию - отправлять письма немедленно. Однако, вы можете хотеть избежать нагрузки производительности коммуникций с почтовым сервером, которая может вызвать ожидание пользователем загрузки следующей страницы, пока отправляются письма. Этого можно избежать, выбрав "спулинг" писем, вместо их прямой отправки.

Это заставляет почтовый сервис не пытаться отправить письмо, а вместо этого сохранить его куда-то, например, в файл. Другой процесс потом может считать из спула и позаботиться об отправке писемв спуле. На данный момент поддерживается только спулинг в файл или память.

Спулинг с использованием памяти

Когда вы используете спулин для сохранения электронных писем в память, они будут отправлены прямо перед завершением ядра. Это означает, что письмо будет отправлено только в случае, если был запрос был полностью выполнен без ошибок и нерешённых исключений. Чтобы сконфигурировать этот спул, используйте следующую конфигурацию:

  • YAML
    1
    2
    3
    4
    # config/packages/swiftmailer.yaml
    swiftmailer:
        # ...
        spool: { type: memory }
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    <!-- config/packages/swiftmailer.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:swiftmailer="http://symfony.com/schema/dic/swiftmailer"
        xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
            http://symfony.com/schema/dic/swiftmailer http://symfony.com/schema/dic/swiftmailer/swiftmailer-1.0.xsd">
    
        <swiftmailer:config>
            <swiftmailer:spool type="memory" />
        </swiftmailer:config>
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    // config/packages/swiftmailer.php
    $container->loadFromExtension('swiftmailer', array(
         // ...
        'spool' => array('type' => 'memory'),
    ));
    

Спулинг с использованием файлов

Когда вы используете файловую систему для спулинга, Symfony создаёт папу в заданном пути для каждого сервиса почты (например, "default" для сервиса по умолчанию). Эта папка будет содержать файлы для каждого письма в спуле. Так что убедитесь, что этот каталог может быть написан Symfony (или вашим веб-сервером/php)!

Чтобы исползовать спул с файлами, используйте следующую конфигурацию:

  • YAML
    1
    2
    3
    4
    5
    6
    # config/packages/swiftmailer.yaml
    swiftmailer:
        # ...
        spool:
            type: file
            path: /path/to/spooldir
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    <!-- config/packages/swiftmailer.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:swiftmailer="http://symfony.com/schema/dic/swiftmailer"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd
            http://symfony.com/schema/dic/swiftmailer http://symfony.com/schema/dic/swiftmailer/swiftmailer-1.0.xsd">
    
        <swiftmailer:config>
            <swiftmailer:spool
                type="file"
                path="/path/to/spooldir"
            />
        </swiftmailer:config>
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // config/packages/swiftmailer.php
    $container->loadFromExtension('swiftmailer', array(
         // ...
    
        'spool' => array(
            'type' => 'file',
            'path' => '/path/to/spooldir',
        ),
    ));
    

Tip

Если вы хотите хранить спул где-либо в каталоге вашего проекта, помните, что вы можете использовать параметр %kernel.project_dir% для отсылки к корню проекта:

1
path: '%kernel.project_dir%/var/spool'

Теперь, когда ваше приложение отправляет электронное письмо, оно на самом деле не будет отправлено, а будет добавлено в спул. Отправка сообщений из спула совершается отдельно. Существует консольная команда для отправки писем из спула:

1
$ php bin/console swiftmailer:spool:send --env=prod

Она имеет опцию для лимитирования количества писем, которые будут отправлены:

1
$ php bin/console swiftmailer:spool:send --message-limit=10 --env=prod

Вы также можете установить временной лимит в секундах:

1
$ php bin/console swiftmailer:spool:send --time-limit=10 --env=prod

Конечно вам не захочется запускать это вручную в реальной жизни. Вместо этого, консольная команда должна вызываться работой крона или запланированным заданием и выполняться с регулярными интервалами.

Caution

Когда вы создаёте письмо с SwiftMailer, он генерирует класс Swift_Message. Если сервис swiftmailer был загружен лениво, он генерирует вместо этого класс прокси под названием Swift_Message_<someRandomCharacters>.

Если для спула вы используете память, это изменение прозрачно и не имеет никакого влияния. Но при использовании файловой системы для спула, класс сообщения преобразовывается в последовательную форму в файле со случайным именем класса. Проблема в том, что это случайное имя класса изменяется при каждой очистке кеша. Так что если вы отправляете письмо, а потом очищаете кеш, то письмо не будет преобразовано в последовательную форму.

При следующем выполнении swiftmailer:spool:send будет возникать ошибка, так как класс Swift_Message_<someRandomCharacters> не существует (больше).

Решением может быть либо использование памяти для спула, или загрузка сервиса
swiftmailer без опции lazy (см. Ленивые сервисы).

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.