如何滚动发送邮件

3.4 版本
维护中的版本

当你在Symfony程序中使用SwiftmailerBundle发送邮件时,默认是邮件立即被发出。你可能希望,避免“Swift Mailer与邮件传输”之间的性能冲击,因为在邮件送出时会引发用户等待而难于加载下一个页面。要避免这个可以选择“spool”(滚动)邮件而不是直接发送它们。这意味着Swift Mailer并不试图发出邮件而是把相关信息存到某处,比如一个文件中。另外的进程会从spool中读取(那些信息)并且解决滚动发送的问题。目前,Swift Mailer仅支持(把邮件信息)spool(存入)到文件或内存。

使用内存来滚动 

当你使用spooling把邮件存入内存时,它们会在kernel结束时被立即发送。这表明,邮件只在“完整的请求被执行,且没有任何未处置的异常或没有任何错误”的时候才被发送。要在swiftmailer中对内存选项进行配置,使用以下内容:

1
2
3
4
# app/config/config.yml
swiftmailer:
    # ...
    spool: { type: memory }
1
2
3
4
5
6
7
8
9
10
11
12
<!-- app/config/config.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>
1
2
3
4
5
// app/config/config.php
$container->loadFromExtension('swiftmailer', array(
     // ...
    'spool' => array('type' => 'memory')
));

使用文件来滚动 

当你对spooling使用文件系统时,Symfony会在给定的目录下为每一个邮件服务(如,默认的邮件服务就是“default”)创建一个文件夹。这个文件夹内含滚动轴(spool)上面每一封邮件所对应的文件。因此要确保目录可被Symfony(或你的webserver/php)写入!

为了使用文件方式的滚动,使用下列配置:

1
2
3
4
5
6
# app/config/config.yml
swiftmailer:
    # ...
    spool:
        type: file
        path: /path/to/spooldir
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- app/config/config.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>
1
2
3
4
5
6
7
8
9
// app/config/config.php
$container->loadFromExtension('swiftmailer', array(
     // ...
 
    'spool' => array(
        'type' => 'file',
        'path' => '/path/to/spooldir',
    ),
));

如果你希望把滚动信息存放于项目中的其他某个目录,记得要使用 %kernel.root_dir% 参数来引用项目根目录:

1
path: '%kernel.root_dir%/spool'

现在,当你的程序发送邮件时,并不真正发送,而是添加到spool中。从滚动轴发送信息是单独完成的。有一个命令用于发送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

在现实中,你当然不希望手动完成这些。命令行应当被一个cron job,或是由一个运行于规律间隔的计划任务来触发。

当你使用SwiftMailer来创建信息时,它会生成一个 Swift_Message 类。如果 swiftmailer 服务是lazy loaded的,它会生成另一个名为 Swift_Message_<someRandomCharacters> 的代理类(proxy class)。

如果你使用memory spool,这种改变是透明的并且没有任何性能损失。但在使用filesystem spool时,message class将在一个文件中以一个随机类名被序列化。问题就在于这个随机的类名在每次清理缓存时会发生改变。因此,如果你发送邮件之后就清除缓存,邮件信息将无法被反序列化。

在下一次的 swiftmailer:spool:send 执行过程中会报错,因为 Swift_Message_<someRandomCharacters> 类不(再)存在。

解决方案可以是 memory spool 或者加载 swiftmailer 服务时不使用 lazy 选项 (见 Lazy Services)。

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)