A simple way to queue e-mail using Zend_Mail
Hello.
I want to share very simple and easy way of e-mail queues using Zend_Mail. The examples in the article is intentionally made as simple as possible and not tied to the framework, because the aim of the article is to show method and not a specific implementation. In addition, this solution does not have to be used within Zend Framework, it is easy to fit into any project.
Straight to the point. We need:
table in the database;
class transport;
file implements sending messages (run for the crown).
First define the database table:
the
Next, create a class of our transport system:
the
All of which makes this class, it receives the already prepared data from Zend_Mail and stores them in the database. If you create an entry in a table failed, throws an exception Zend_Mail_Transport_Exception.
Well, the file that implements the sending of message assume that the file is in a separate folder in the application root:
the
Use of queue:
the
Accordingly, if you need to send a message to the queue, using mail () to not pass a car or pass null.
P. S. Maybe someone will consider it more correct to use Zend_Queue, and perhaps will be right. I in any case do not claim that the method described in the article is the only solution. Solutions are always a lot, I have described only one of them.
P. P. S. special thanks for useful comments to users markPnk and gen.
Article based on information from habrahabr.ru
I want to share very simple and easy way of e-mail queues using Zend_Mail. The examples in the article is intentionally made as simple as possible and not tied to the framework, because the aim of the article is to show method and not a specific implementation. In addition, this solution does not have to be used within Zend Framework, it is easy to fit into any project.
Straight to the point. We need:
table in the database;
class transport;
file implements sending messages (run for the crown).
First define the database table:
the
CREATE TABLE email_queue (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
recipients TEXT NOT NULL,
subject CHAR(255) NOT NULL,
message TEXT NOT NULL,
header TEXT NOT NULL,
parameters TEXT
max_attempts TINYINT UNSIGNED NOT NULL DEFAULT 3,
attempts TINYINT UNSIGNED NOT NULL DEFAULT 0,
is_false TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
in_process INT UNSIGNED DEFAULT NULL DEFAULT 0,
time_last_attempt INT UNSIGNED DEFAULT NULL,
create_time INT UNSIGNED NOT NULL
);
Next, create a class of our transport system:
the
class Zend_Mail_Transport_Sendmail extends EmailQueueTransport
{
/**
* Send mail using EmailQueue
*
* @access public
* @return void
* @throws Zend_Mail_Transport_Exception If parameters is set but not a string
* @throws Zend_Mail_Transport_Exception If failed to add a message in queue
*/
public function _sendMail()
{
if ($this->parameters !== null && !is_string($this->parameters)) {
/**
* Exception is thrown here because the $parameters is a public property
*/
throw new Zend_Mail_Transport_Exception('Parameters were set but are not a string');
}
$db = Zend_Db_Table_Abstract::getDefaultAdapter();
$statement = $db->prepare('
INSERT email_queue
SET recipients = to :recipients
subject = :subject,
message = :message,
header = :header,
parameters = :parameters
create_time = :create_time
');
$result = $statement->execute(array(
'recipients' => $this->recipients,
'subject' => $this- > _mail- > getSubject(),
'message' => $this->body,
'header' => $this->header
'parameters' => $this->parameters,
'create_time' = > time()
));
if (!$result) {
throw new Zend_Mail_Transport_Exception(
'Failed to add a message in queue.');
}
}
}
All of which makes this class, it receives the already prepared data from Zend_Mail and stores them in the database. If you create an entry in a table failed, throws an exception Zend_Mail_Transport_Exception.
Well, the file that implements the sending of message assume that the file is in a separate folder in the application root:
the
<?php
/**
* Add the messages in the log
*
* @param type $message
* @return void
*/
function set_log($message)
{
$message = date('H:i d.m.Y ', time()) . $message . "\r\n";
$logFile = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'logs' . DIRECTORY_SEPARATOR . basename(__FILE__, '.php') . '.log';
error_log($message, 3, $logFile);
}
try {
$config = include realpath(dirname(__FILE__) . '/../') . '/application/config/config.php'; // Path to config file
$configDb = $config['db']['params'];
$db = new PDO(
'mysql:host=' . $configDb['host'] . ';dbname=' . $configDb['dbname'],
$configDb['username'],
$configDb['password'],
array(
PDO::MYSQL_ATTR_INIT_COMMAND = > "SET NAMES 'utf8'",
'profiler' => false,
)
);
} catch (PDOException $e) {
set_log('Connection error:' . $e->getMessage());
}
$limit = 100; // limit rows
$processLimitTime = 600; // 10 minutes
$statement = $db->query('
SELECT *
FROM email_queue
WHERE attempts < max_attempts
AND in_process < ' . (time() - $processLimitTime) . '
ORDER BY id ASC
LIMIT ' . $limit
);
$rows = $statement- > fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $row) {
$db->beginTransaction();
$result = $db- > exec('
UPDATE email_queue
SET in_process = ' . time() . '
WHERE id = ' . $row['id']
);
if (!$result) {
set_log('Error when updating record from the table "email_queue". Id queue is ' . $row['id'] . '.');
continue;
}
$sent = mail(
$row['recipients'],
$row['subject'],
$row['message'],
$row['header'],
$row['parameters']
);
$db->commit();
if ($sent) {
$result = $db- > exec('DELETE from email_queue WHERE id =' . $row['id']);
if (!$result) {
set_log('Error when deleting record from the table "email_queue". Id queue is ' . $row['id'] . '.');
}
} else {
$result = $db- > exec('
UPDATE email_queue
SET is_false = 1,
in_process = 0,
attempts = ' . ($row['attempts'] + 1) . '
WHERE id = ' . $row['id']
);
if (!$result) {
set_log('Error when updating record from the table "email_queue". Id queue is ' . $row['id'] . '.');
}
set_log('Error when sending messages to e-mail. Id queue is ' . $row['id'] . 'e-mails is' . $row['recipients'] . '.');
}
}
Use of queue:
the
$mail = new Zend_Mail();
$mail- > setFrom($from);
$mail->addTo($to);
$mail- > setBodyHtml($body);
$mail->setSubject($subject);
$transport = new \EmailQueueTransport();
$mail- > send($transport);
Accordingly, if you need to send a message to the queue, using mail () to not pass a car or pass null.
P. S. Maybe someone will consider it more correct to use Zend_Queue, and perhaps will be right. I in any case do not claim that the method described in the article is the only solution. Solutions are always a lot, I have described only one of them.
P. P. S. special thanks for useful comments to users markPnk and gen.
Comments
Post a Comment