View Source

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[{zone-template-instance:ZFDEV:Zend Proposal Zone Template}

{zone-data:component-name}
Zend_Mail_Transport_Queue
{zone-data}

{zone-data:proposer-list}
* [Simon Mundy|mailto:studio@peptolab.com]
* [~alexander]
** (Zend-liaison)
{zone-data}

{zone-data:revision}
0.1 - 1 October 2007: Initial proposal.
{zone-data}

{zone-data:overview}
Zend_Mail_Transport_Queue is designed to manage the delivery of a large volume of mail. It provides a number of backends by which to store the mail and then allows deferred delivery from the storage container using concrete transport methods from a separate script.
{zone-data}

{zone-data:references}
* [PEAR Mail_Queue|http://pear.php.net/manual/en/package.mail.mail-queue.php]
{zone-data}

{zone-data:requirements}
* This component *will* provide an interface to allow the creation of multiple backends.
* This component *will not* send mail after a developer-specified amount of retries.
* This component *will* allow the developer to pass any valid transport component to re-send mail.
* This component *will* provide a means for passing log instances.
{zone-data}

{zone-data:dependencies}
* Zend_Mail
* Zend_Mail_Transport_Abstract
{zone-data}

{zone-data:operation}
This transport type replaces an existing SMTP or Sendmail transport instance. A concrete storage adapter is instantiated (e.g. Zend_Mail_Transport_Queue_Db or Zend_Mail_Transport_Queue_File) and then used as the transport to dispatch mail in the usual manner.

A secondary script (run as a cron job, scheduled task or as a trigger during another script's execution) will then access the transport's static process method. During this time mail is processed and directed to a specified transport (e.g. SMTP or Sendmail) and sent as normal. Processing will be limited to an amount configurable by the developer. If a mail instance cannot be sent (i.e. throws a Zend_Mail_Transport_Exception or Zend_Mail_Protocol_Exception exception) the mail will be requeued for a specified amount of retries (default is 10).

When mail is processed (success or failure) Zend_Mail_Transport_Queue will also log the attempt if a Zend_Log adapter is made available. The content and format of the log message is also developer-configurable.
{zone-data}

{zone-data:milestones}
* Milestone 1: [design notes will be published here|http://framework.zend.com/wiki/x/sg]
* Milestone 2: Working prototype checked into the incubator supporting use cases #1, #2, ...
* Milestone 3: Working prototype checked into the incubator supporting use cases #3 and #4.
* Milestone 4: Unit tests exist, work, and are checked into SVN.
* Milestone 5: Initial documentation exists.
{zone-data}

{zone-data:class-list}
* Zend_Mail_Transport_Queue_Interface
* Zend_Mail_Transport_Queue_Abstract
* Zend_Mail_Transport_Queue_Db
* Zend_Mail_Transport_Queue_File
{zone-data}

{zone-data:use-cases}
{composition-setup}
{deck:id=Usecase}
{card:label=UC 01 : Simple usage}
h3. UC 01: Simple usage
Sending mail to the queue
{code}
require_once 'Zend/Mail.php';
require_once 'Zend/Mail/Transport/Queue/File.php';

// Tags mail in the queue with 'mynewslettergroup'
$options = array('groupId' => 'mynewslettergroup');

$tr = new Zend_Mail_Transport_Queue_File('/path/to/my/queue', $options);

$mail = new Zend_Mail();
$mail->setFrom('someone@somewhere.com')
->addTo('someone@somewhere.com')
->setBodyText('A queued message')
->send($tr);
{code}
Processing the queue from a separate cron script
{code}
#!/usr/bin/php
<?php

// Set default paths
set_include_path(join(PATH_SEPARATOR, array(realpath('/path/to/zend/library'),
get_include_path())));

require_once 'Zend/Mail.php';
require_once 'Zend/Mail/Transport/Queue/File.php';

// Only processes mail in the queue tagged with Group Id of 'mynewslettergroup'
$options = array('groupId' => 'mynewslettergroup'
'limit' => 10,
'retries' => 10);

// Will use default transport (sendmail) if no explicit transport is set.
Zend_Mail_Transport_Queue_Db::process('/path/to/my/queue', $options);
{code}
{card}

{card:label=UC 02: Advanced usage with DB and Logger}
h3. UC 02: Advanced usage with DB and Logger
Sending mail to the queue
{code}
require_once 'Zend/Db.php';
require_once 'Zend/Mail.php';
require_once 'Zend/Mail/Transport/Queue/Db.php';

// Tags mail in the queue with 'mynewslettergroup'
$options = array('table' => 'mailqueue',
'groupId' => 'mynewslettergroup');

// See example schema below
$db = Zend_Db::factory('pdo_mysql', array('dbhost' => 'localhost',
'username' => 'mailqueue',
'password' => 'mailqueue',
'dbname' => 'mailqueue'));

$tr = new Zend_Mail_Transport_Queue_Db($db, $options);

$mail = new Zend_Mail();
$mail->setFrom('someone@somewhere.com')
->addTo('someone@somewhere.com')
->setBodyText('A queued message')
->send($tr);
{code}
Processing the queue from a separate cron script
{code}
#!/usr/bin/php
<?php

// Set default paths
set_include_path(join(PATH_SEPARATOR, array(realpath('/path/to/zend/library'),
get_include_path())));

require_once 'Zend/Db.php';
require_once 'Zend/Mail.php';
require_once 'Zend/Log.php';
require_once 'Zend/Log/Writer/Stream.php';
require_once 'Zend/Mail/Transport/Smtp.php';
require_once 'Zend/Mail/Transport/Queue/Db.php';

// Only processes mail in the queue tagged with Group Id of 'mynewslettergroup'
$options = array('table' => 'mailqueue',
'groupId' => 'mynewslettergroup',
'limit' => 10,
'retries' => 10);

// See example schema below
$db = Zend_Db::factory('pdo_mysql', array('dbhost' => 'localhost',
'username' => 'mailqueue',
'password' => 'mailqueue',
'dbname' => 'mailqueue'));

$tr = new Zend_Mail_Transport_Smtp('localhost');
$log = new Zend_Log(new Zend_Log_Writer_Stream('/path/to/logfile'));

Zend_Mail_Transport_Queue_Db::process($db, $options, $tr, $log);
{code}
Example database schema for mailqueue
{code}
CREATE TABLE IF NOT EXISTS `mailqueue` (
`id` int(10) unsigned NOT NULL auto_increment,
`groupid` varchar(255) collate utf8_unicode_ci default NULL,
`subject` varchar(255) collate utf8_unicode_ci default NULL,
`sender` varchar(255) collate utf8_unicode_ci default NULL,
`recipient` varchar(255) collate utf8_unicode_ci default NULL,
`message` text collate utf8_unicode_ci,
`attempts` int(10) unsigned NOT NULL default '0',
`sent` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `groupid` (`groupid`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='List of queued mail messages for Zend_Mail_Transport_DbQueue' ;
{code}
{card}
{deck}
{zone-data}

{zone-data:skeletons}
{code}
abstract class Zend_Mail_Transport_Queue_Abstract extends Zend_Mail_Transport_Abstract
{
/**
* Config options for authentication
*
* @var array
*/
protected $_config = array('groupId' => 'default',
'limit' => 10,
'retry' => 10,
'setDeliverTimestamp' => false,
'archiveDelivered' => false,
'deliverTimestamp' => 'Y-m-d H:i:s',
'logMessageDeliver' => '[%s] delivered: subject=%s to=%s from=%s id=%s',
'logMessageError' => '[%s] failed: subject=%s to=%s from=%s id=%s');


/**
* Send an email to the database queue
*
* Every individual recipient is inserted as a separate row. These rows accumulate in the
* queue until they are manually processed.
*
* @return void
*/
abstract public function _sendMail();



/**
* Process rows in the database queue
*
* @return int Number of rows successfully processed
*/
static public function process($containerId, $options, $transport = null, $log = null) {}
}

class Zend_Mail_Transport_Queue_Db extends Zend_Mail_Transport_Queue_Abstract
{
const FIELD_ID = 'id';
const FIELD_GROUPID = 'groupid';
const FIELD_SENDER = 'sender';
const FIELD_RECIPIENT = 'recipient';
const FIELD_SUBJECT = 'subject';
const FIELD_MESSAGE = 'message';
const FIELD_ATTEMPTS = 'attempts';
const FIELD_SCHEDULE = 'schedule';
const FIELD_STATUS = 'status';
const FIELD_SENT = 'sent';

/**
* Database connection
*
* @var string
*/
protected $_db;


/**
* Config options for authentication
*
* @var array
*/
protected $_schema = array(self::FIELD_ID => 'id',
self::FIELD_GROUPID => 'groupid',
self::FIELD_SENDER => 'sender',
self::FIELD_RECIPIENT => 'recipient',
self::FIELD_SUBJECT => 'subject',
self::FIELD_MESSAGE => 'message',
self::FIELD_ATTEMPTS => 'attempts',
self::FIELD_SENT => 'sent',
self::FIELD_STATUS => 'status');


/**
* Constructor.
*
* @param Zend_Db_Adapter_Abstract $db
* @param string $table
* @param array|null $config OPTIONAL (Default: array)
* @return void
*/
public function __construct(Zend_Db_Adapter_Abstract $db, Array $config = array()) {}


/**
* Process rows in the database queue
*
* @return int Number of rows successfully processed
*/
static public function process(Zend_Db_Adapter_Abstract $db, Array $config = array(),
Zend_Mail_Transport_Abstract $transport = null,
Zend_Log $log = null) {}

}
{code}
{zone-data}

{zone-template-instance}]]></ac:plain-text-body></ac:macro>