added mail send queue

This commit is contained in:
JT Smith 2006-03-21 03:27:57 +00:00
parent b062e61508
commit 7c71d93c1e
6 changed files with 263 additions and 44 deletions

View file

@ -29,6 +29,7 @@
otherwise be slow or complex pages. More details in migration.txt.
- The SMTP mail backend has been replaced with a new API that's capable of
sending attachments, HTML messages, and more. This will introduce many new
- Added a mail queue system.
options for developers.
- The group mail screen now allows sending of HTML messages.
- Added prequery statements to the SQLReport and configurable allowed statements

View file

@ -134,6 +134,11 @@ sub addWorkflow {
value text,
primary key (activityId, name)
)");
$session->db->write("create table mailQueue (
messageId varchar(22) binary not null primary key,
message mediumtext,
toGroup varchar(22) binary
)");
print "\t\tPurging old workflow info.\n";
my $versionTag = WebGUI::VersionTag->getWorking($session);
$versionTag->set({name=>"Upgrade to ".$toVersion});
@ -164,6 +169,7 @@ sub addWorkflow {
"WebGUI::Workflow::Activity::ExpireGroupings", "WebGUI::Workflow::Activity::PurgeOldAssetRevisions",
"WebGUI::Workflow::Activity::ExpireSubscriptionCodes", "WebGUI::Workflow::Activity::PurgeOldTrash",
"WebGUI::Workflow::Activity::GetSyndicatedContent", "WebGUI::Workflow::Activity::ProcessRecurringPayments",
"WebGUI::Workflow::Activity::SendQueuedMailMessages",
"WebGUI::Workflow::Activity::SyncProfilesToLdap", "WebGUI::Workflow::Activity::SummarizePassiveProfileLog"],
"WebGUI::User"=>["WebGUI::Workflow::Activity::CreateCronJob", "WebGUI::Workflow::Activity::NotifyAboutUser"],
"WebGUI::VersionTag"=>["WebGUI::Workflow::Activity::CommitVersionTag", "WebGUI::Workflow::Activity::RollbackVersionTag",
@ -304,6 +310,23 @@ sub addWorkflow {
$activity->set("subject", "Content Denied");
$activity->set("message", "Your version tag was denied. Please take corrective actions and recommit your changes.");
$activity->set("who", "committer");
$workflow = WebGUI::Workflow->create($session, {
title=>"Send Queued Email Messages",
description => "Sends all the messages in the mail queue.",
enabled=>1,
isSerial=>1,
type=>"None"
}, "pbworkflow000000000006");
$activity = $workflow->addActivity("WebGUI::Workflow::Activity::SendQueuedMailMessages", "pbwfactivity0000000021");
$activity->set("title", "Send Queued Messages");
WebGUI::Workflow::Cron->create($session, {
title=>'Send Queued Email Messages Every 5 Minutes',
enabled=>1,
runOnce=>0,
minuteOfHour=>"*/5",
priority=>3,
workflowId=>$workflow->getId
}, "pbcron0000000000000004");
print "\t\tUpdating settings.\n";
$session->setting->remove("autoCommit");
$session->setting->remove("alertOnNewUser");

View file

@ -302,7 +302,8 @@
"WebGUI::Workflow::Activity::ExpireGroupings", "WebGUI::Workflow::Activity::PurgeOldAssetRevisions",
"WebGUI::Workflow::Activity::ExpireSubscriptionCodes", "WebGUI::Workflow::Activity::PurgeOldTrash",
"WebGUI::Workflow::Activity::GetSyndicatedContent", "WebGUI::Workflow::Activity::ProcessRecurringPayments",
"WebGUI::Workflow::Activity::SyncProfilesToLdap", "WebGUI::Workflow::Activity::SummarizePassiveProfileLog"],
"WebGUI::Workflow::Activity::SyncProfilesToLdap", "WebGUI::Workflow::Activity::SummarizePassiveProfileLog",
"WebGUI::Workflow::Activity::SendQueuedMailMessages"],
"WebGUI::User" : ["WebGUI::Workflow::Activity::CreateCronJob", "WebGUI::Workflow::Activity::NotifyAboutUser"],
"WebGUI::VersionTag" : ["WebGUI::Workflow::Activity::CommitVersionTag", "WebGUI::Workflow::Activity::RollbackVersionTag",
"WebGUI::Workflow::Activity::TrashVersionTag", "WebGUI::Workflow::Activity::CreateCronJob",

View file

@ -14,10 +14,13 @@ http://www.plainblack.com info@plainblack.com
=cut
use strict;
use Net::SMTP;
use MIME::Entity;
use MIME::Parser;
use LWP::MediaTypes qw(guess_media_type);
use strict;
use WebGUI::Group;
use WebGUI::User;
=head1 NAME
@ -31,11 +34,15 @@ This package is used for sending emails via SMTP.
use WebGUI::Mail::Send;
my $mail = WebGUI::Mail::Send->new($session, { to=>$to, from=>$from, subject=>$subject});
my $mail = WebGUI::Mail::Send->create($session, { to=>$to, from=>$from, subject=>$subject});
my $mail = WebGUI::Mail::Send->retrieve($session, $messageId);
$mail->addText($text);
$mail->addHtml($html);
$mail->addAttachment($pathToFile);
$mail->send;
$mail->queue;
=head1 METHODS
@ -46,7 +53,7 @@ These methods are available from this class:
#-------------------------------------------------------------------
=head2 addAttachment ( pathToFile )
=head2 addAttachment ( pathToFile [ , mimetype ] )
Adds an attachment to the message.
@ -54,15 +61,20 @@ Adds an attachment to the message.
The filesystem path to the file you wish to attach.
=head3 mimetype
Optionally specify a mime type for this attachment. If one is not specified it will be guessed based upon the file extension.
=cut
sub addAttachment {
my $self = shift;
my $path = shift;
my $mimetype = shift || guess_media_type($path);
$self->{_message}->attach(
Path=>$path,
Encoding=>'-SUGGEST',
Type=>guess_media_type($path)
Type=>$mimetype
);
}
@ -114,9 +126,9 @@ sub addText {
#-------------------------------------------------------------------
=head2 new ( session, headers )
=head2 create ( session, headers )
Constructor.
Creates a new message and returns a WebGUI::Mail::Send object. This is a class method.
=head3 session
@ -130,6 +142,10 @@ A hash reference containing addressing and other header level options.
A string containing a comma seperated list of email addresses to send to.
=head4 toGroup
A WebGUI groupId. The email address of the users in this group will be looked up and will each be sent a copy of this message.
=head4 subject
A short string of text to be placed in the subject line.
@ -156,22 +172,13 @@ A mime type for the message. Defaults to "multipart/mixed".
=cut
sub new {
sub create {
my $class = shift;
my $session = shift;
my $headers = shift;
$headers->{from} ||= $session->setting->get("companyEmail");
$headers->{contentType} ||= "multipart/mixed";
my $override = "";
if ($session->config->get("emailOverride")) {
$override = $headers->{to};
$headers->{to} = $session->config->get("emailOverride");
delete $headers->{bcc};
delete $headers->{cc};
}
my $message = MIME::Entity->build(
Type=>$headers->{contentType},
From=>$headers->{from},
Type=>$headers->{contentType} || "multipart/mixed",
From=>$headers->{from} || $session->setting->get("companyEmail"),
To=>$headers->{to},
Cc=>$headers->{cc},
Bcc=>$headers->{bcc},
@ -180,12 +187,80 @@ sub new {
Date=>$session->datetime->epochToHuman("","%W, %d %C %y %j:%n:%s %O"),
"X-Mailer"=>"WebGUI"
);
if ($override) {
$message->attach(Data=>"This message was intended for ".$override." but was overridden in the config file.\n\n");
if ($session->config->get("emailOverride")) {
my $to = $headers->{to};
$to = "WebGUI Group ".$headers->{toGroup} if ($headers->{toGroup});
$message->head->replace("to", $session->config->get("emailOverride"));
$message->head->replace("cc",undef);
$message->head->replace("bcc",undef);
delete $headers->{toGroup};
$message->attach(Data=>"This message was intended for ".$to." but was overridden in the config file.\n\n");
}
bless {_message=>$message, _session=>$session, _headers=>$headers}, $class;
bless {_message=>$message, _session=>$session, _toGroup=>$headers->{toGroup} }, $class;
}
#-------------------------------------------------------------------
=head2 getMessageIdsInQueue ( session )
Returns an array reference of the message IDs in the mail queue. Use with the retrieve() method. This is a class method.
=head3 session
A reference to the current session.
=cut
sub getMessageIdsInQueue {
my $class = shift;
my $session = shift;
return $session->db->buildArrayRef("select messageId from mailQueue");
}
#-------------------------------------------------------------------
=head2 queue ( )
Puts this message in the mail queue so it can be sent out later by the workflow system. Returns a messageId so that the message can be retrieved later if necessary. Note that this is the preferred method of sending messages because it keeps WebGUI running faster.
=cut
sub queue {
my $self = shift;
return $self->session->db->setRow("mailQueue", "messageId", { messageId=>"new", message=>$self->{_message}->stringify, toGroup=>$self->{_toGroup} });
}
#-------------------------------------------------------------------
=head2 retrieve ( session, messageId )
Retrieves a message from the mail queue, which thusly deletes it from the queue. This is a class method.
=head3 session
A reference to the current session.
=head3 messageId
The unique id for a message in the queue.
=cut
sub retrieve {
my $class = shift;
my $session = shift;
my $messageId = shift;
return undef unless $messageId;
my $data = $session->db->getRow("mailQueue","messageId", $messageId);
return undef unless $data->{messageId};
$session->db->deleteRow("mailQueue","messageId", $messageId);
my $parser = MIME::Parser->new;
bless {_session=>$session, _message=>$parser->parse_data($data->{messageId}), _toGroup=>$data->{toGroup}}, $class;
}
#-------------------------------------------------------------------
=head2 send ( )
@ -196,31 +271,50 @@ Sends the message via SMTP. Returns 1 if successful.
sub send {
my $self = shift;
if ($self->session->setting->get("smtpServer") =~ /\/sendmail/) {
if (open(MAIL,"| ".$self->session->setting->get("smtpServer")." -t -oi -oem")) {
$self->{_message}->print(\*MAIL);
close(MAIL) or $self->session->errorHandler->error("Couldn't close connection to mail server: ".$self->session->setting->get("smtpServer"));
my $status = 1;
if ($self->{_message}->head->get("To")) {
if ($self->session->setting->get("smtpServer") =~ /\/sendmail/) {
if (open(MAIL,"| ".$self->session->setting->get("smtpServer")." -t -oi -oem")) {
$self->{_message}->print(\*MAIL);
close(MAIL) or $self->session->errorHandler->error("Couldn't close connection to mail server: ".$self->session->setting->get("smtpServer"));
} else {
$self->session->errorHandler->error("Couldn't connect to mail server: ".$self->session->setting->get("smtpServer"));
$status = 0;
}
} else {
$self->session->errorHandler->error("Couldn't connect to mail server: ".$self->session->setting->get("smtpServer"));
return 0;
}
} else {
my $smtp = Net::SMTP->new($self->session->setting->get("smtpServer")); # connect to an SMTP server
if (defined $smtp) {
$smtp->mail($self->{_headers}{from}); # use the sender's address here
$smtp->to(split(",",$self->{_headers}{to})); # recipient's address
$smtp->cc(split(",",$self->{_headers}{cc}));
$smtp->bcc(split(",",$self->{_headers}{bcc}));
$smtp->data(); # Start the mail
$smtp->datasend($self->{_message}->stringify);
$smtp->dataend(); # Finish sending the mail
$smtp->quit; # Close the SMTP connection
} else {
$self->session->errorHandler->error("Couldn't connect to mail server: ".$self->session->setting->get("smtpServer"));
return 0;
my $smtp = Net::SMTP->new($self->session->setting->get("smtpServer")); # connect to an SMTP server
if (defined $smtp) {
$smtp->mail($self->{_message}->head->get("from")); # use the sender's address here
$smtp->to(split(",",$self->{_message}->head->get("to"))); # recipient's address
$smtp->cc(split(",",$self->{_message}->head->get("cc")));
$smtp->bcc(split(",",$self->{_message}->head->get("bcc")));
$smtp->data(); # Start the mail
$smtp->datasend($self->{_message}->stringify);
$smtp->dataend(); # Finish sending the mail
$smtp->quit; # Close the SMTP connection
} else {
$self->session->errorHandler->error("Couldn't connect to mail server: ".$self->session->setting->get("smtpServer"));
$status = 0;
}
}
}
return 1;
my $group = $self->{_toGroup};
delete $self->{_toGroup};
if ($group) {
my $group = WebGUI::Group->new($self->session, $self->{_toGroup});
$self->{_message}->head->replace("bcc", undef);
$self->{_message}->head->replace("cc", undef);
foreach my $userId (@{$group->getUsers(1,1)}) {
my $user = WebGUI::User->new($self->session, $userId);
if ($user->profileField("email")) {
$self->{_message}->head->replace("To",$user->profileField("email"));
unless ($self->send) {
$status = 0;
}
}
}
}
return $status;
}
#-------------------------------------------------------------------

View file

@ -0,0 +1,88 @@
package WebGUI::Workflow::Activity::SendQueuedMailMessages;
=head1 LEGAL
-------------------------------------------------------------------
WebGUI is Copyright 2001-2006 Plain Black Corporation.
-------------------------------------------------------------------
Please read the legal notices (docs/legal.txt) and the license
(docs/license.txt) that came with this distribution before using
this software.
-------------------------------------------------------------------
http://www.plainblack.com info@plainblack.com
-------------------------------------------------------------------
=cut
use strict;
use base 'WebGUI::Workflow::Activity';
use WebGUI::Mail::Send;
=head1 NAME
Package WebGUI::Workflow::Activity::SendQueuedMailMessages
=head1 DESCRIPTION
Sends all the messages in the mail queue.
=head1 SYNOPSIS
See WebGUI::Workflow::Activity for details on how to use any activity.
=head1 METHODS
These methods are available from this class:
=cut
#-------------------------------------------------------------------
=head2 definition ( session, definition )
See WebGUI::Workflow::Activity::defintion() for details.
=cut
sub definition {
my $class = shift;
my $session = shift;
my $definition = shift;
my $i18n = WebGUI::International->new($session, "Workflow_Activity_SendQueuedMailMessages");
push(@{$definition}, {
name=>$i18n->get("topicName"),
properties=> { }
});
return $class->SUPER::definition($session,$definition);
}
#-------------------------------------------------------------------
=head2 execute ( )
See WebGUI::Workflow::Activity::execute() for details.
=cut
sub execute {
my $self = shift;
foreach my $id (@{WebGUI::Mail::Send->getMessageIdsInQueue($self->session)}) {
my $message = WebGUI::Mail::Send->retrieve($self->session, $id);
if (defined $message) {
unless ($message->send) {
# if the message fails to send, requeue it
$message->queue;
}
}
}
return $self->COMPLETE;
}
1;

View file

@ -0,0 +1,12 @@
package WebGUI::i18n::English::Workflow_Activity_SendQueuedMailMessages;
our $I18N = {
'topicName' => {
message => q|Send Queued Mail Messages|,
context => q|The name of this workflow activity.|,
lastUpdated => 0,
},
};
1;