274 lines
7.5 KiB
Perl
274 lines
7.5 KiB
Perl
package WebGUI::Mailing::Email;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use HTML::TreeBuilder;
|
|
use WebGUI::HTML;
|
|
use WebGUI::Mailing::Bounce;
|
|
|
|
use base 'WebGUI::Crud';
|
|
|
|
#----------------------------------------------------------------------------
|
|
sub crud_definition {
|
|
my $class = shift;
|
|
my $session = shift;
|
|
|
|
my $definition = $class->SUPER::crud_definition( $session );
|
|
|
|
$definition->{ tableName } = 'Mailing_email';
|
|
$definition->{ tableKey } = 'mailId';
|
|
$definition->{ sequenceKey } = 'mailingId';
|
|
|
|
my %properties = (
|
|
mailingId => {
|
|
fieldType => 'guid',
|
|
},
|
|
userId => {
|
|
fieldType => 'guid',
|
|
},
|
|
recipientEmail => {
|
|
fieldType => 'email',
|
|
defaultValue => undef,
|
|
},
|
|
status => {
|
|
fieldType => 'text',
|
|
defaultValue => 'queued', # Allowed are: 'queued', 'sent', 'error', 'bounced'
|
|
},
|
|
errorMessage => {
|
|
fieldType => 'text',
|
|
defaultValue => undef,
|
|
},
|
|
isTest => {
|
|
fieldType => 'yesNo',
|
|
defaultValue => 1, # For safety: explicitly turn this off to send real emails
|
|
},
|
|
sendDate => {
|
|
fieldType => 'dateTime',
|
|
},
|
|
sentTo => {
|
|
fieldType => 'text',
|
|
},
|
|
bounceReason => {
|
|
fieldType => 'text',
|
|
},
|
|
);
|
|
|
|
$definition->{ properties } = {
|
|
%{ $definition->{ properties } || {} },
|
|
%properties,
|
|
};
|
|
|
|
return $definition;
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
sub getMailing {
|
|
my $self = shift;
|
|
my $session = $self->session;
|
|
|
|
require WebGUI::Mailing;
|
|
my $mailing = WebGUI::Mailing->new( $session, $self->get('mailingId') );
|
|
#### TODO: error checking;
|
|
return $mailing;
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
sub getQueuedTestEmails {
|
|
my $class = shift;
|
|
my $session = shift;
|
|
|
|
my $it = $class->getAllIterator( $session, {
|
|
constraints => [
|
|
{ 'isTest=?' => [ 1 ] },
|
|
{ 'status=?' => [ 'queued' ] },
|
|
],
|
|
} );
|
|
|
|
return $it;
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
sub getQueued {
|
|
my $class = shift;
|
|
my $session = shift;
|
|
my $mailingId = shift;
|
|
|
|
my $it = $class->getAllIterator( $session, {
|
|
constraints => [
|
|
{ 'mailingId=?' => [ $mailingId ] },
|
|
{ 'isTest=?' => [ 0 ] },
|
|
{ 'status=?' => [ 'queued' ] },
|
|
],
|
|
} );
|
|
|
|
return $it;
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
sub error {
|
|
my $self = shift;
|
|
my $message = shift;
|
|
|
|
$self->update( {
|
|
status => 'error',
|
|
errorMessage => $message || 'No error message available',
|
|
} );
|
|
|
|
return;
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
sub absolutifyURIs {
|
|
my $self = shift;
|
|
my $content = shift;
|
|
my $pageUrl = shift;
|
|
my $siteUrl = $self->session->url->getSiteURL;
|
|
|
|
my $tb = HTML::TreeBuilder->new;
|
|
my $root = $tb->parse( $content );
|
|
|
|
foreach my $link ( @{ $root->extract_links } ) {
|
|
my ($uri, $element, $attr, $tag) = @{ $link };
|
|
if ( $uri !~ m{ ^ (?: [a-z]+:// | \# | mailto: ) }xmsi ) {
|
|
my $new =
|
|
( $uri =~ m{ ^ / }xmsi ) # Is url absolute?
|
|
? $siteUrl . $uri
|
|
: $siteUrl . $pageUrl . '/' . $uri
|
|
;
|
|
|
|
# replace attribute
|
|
$element->attr( $attr, $new );
|
|
}
|
|
}
|
|
|
|
return $tb->as_HTML;
|
|
}
|
|
|
|
sub transformToText {
|
|
my $self = shift;
|
|
my $html = shift;
|
|
|
|
my $text = $html;
|
|
#HTML::Entities::decode($text);
|
|
$text =~ s/<a.*?href=["'](.*?)['"].*?>(.+?)<\/a>/$2 ($1)/g;
|
|
$text = WebGUI::HTML::html2text($text);
|
|
|
|
return $text;
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
sub send {
|
|
my $self = shift;
|
|
my $session = $self->session;
|
|
my $id = $session->id;
|
|
|
|
#### TODO: Error checking
|
|
my $mailing = $self->getMailing;
|
|
unless ( $mailing ) {
|
|
$session->log->error( 'Cannot send because getMailing doesn\'t return one.' );
|
|
return;
|
|
}
|
|
|
|
my $configuration = $mailing->get('configuration') || {};
|
|
my $asset = $mailing->getAsset;
|
|
my $content = $asset->processContentAsUser( $mailing->get('issueId'), $self->get('userId'), $configuration );
|
|
my $body = $self->absolutifyURIs( $content, $asset->getUrl );
|
|
my $text = $self->transformToText( $body );
|
|
|
|
# Mail is a test mail but there is noone to send the result to
|
|
if ( $self->get( 'isTest' ) && !$self->get('recipientEmail') ) {
|
|
$self->error( 'Cannot send test mails without an override recipient address' );
|
|
return;
|
|
}
|
|
|
|
# Determine recipients email address and bail out if we can't find one.
|
|
my $to = $self->get('recipientEmail') || $self->user->get('email');
|
|
if ( !$to ) {
|
|
$self->error( 'Cannot find an email address for this user' );
|
|
return;
|
|
}
|
|
|
|
# Check bounce score
|
|
my $bounceScoreOk = WebGUI::Mailing::Bounce->new( $session )->bounceScoreOk( $to );
|
|
if ( !$self->get( 'isTest' ) && !$bounceScoreOk ) {
|
|
$self->update( {
|
|
status => 'skipped',
|
|
sendDate => time,
|
|
errorMessage => "Bounce score for $to too high",
|
|
} );
|
|
|
|
return;
|
|
}
|
|
|
|
# Fetch subject
|
|
my $subject = $asset->getSubject( $configuration );
|
|
|
|
my $messageId = $id->toHex( $self->getId );
|
|
my $domain = $session->setting->get( 'newsletterReturnDomain' );
|
|
|
|
# Setup email
|
|
my $mail = WebGUI::Mail::Send->create( $session, {
|
|
# from => 'martin@geefmegeld.nl',
|
|
to => $to,
|
|
subject => $subject,
|
|
messageId => "$messageId\@$domain",
|
|
returnPath => "$messageId-bounce\@$domain",
|
|
contentType => 'multipart/alternative',
|
|
} );
|
|
$mail->addText( $text );
|
|
$mail->addHtml( $body );
|
|
|
|
if ( $asset->can( 'getListHeaders' ) ) {
|
|
my $listHeaders = $asset->getListHeaders( $self->user->get('email') );
|
|
|
|
while ( my ($header, $value) = each %{ $listHeaders } ) {
|
|
$mail->addHeaderField( $header, $value );
|
|
}
|
|
}
|
|
|
|
# And send it.
|
|
my $success = $mail->send;
|
|
|
|
if ( $success ne '1' ) {
|
|
$self->error( "Mail couldn't be sent by WebGUI::Mail::Send" );
|
|
}
|
|
else {
|
|
$self->update( {
|
|
status => 'sent',
|
|
sendDate => time,
|
|
sentTo => $to,
|
|
} );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
sub user {
|
|
my $self = shift;
|
|
my $session = $self->session;
|
|
|
|
my $user = WebGUI::User->new( $session, $self->get('userId') );
|
|
return $user;
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
sub registerBounced {
|
|
my $self = shift;
|
|
my $reason = shift;
|
|
my $message = shift;
|
|
|
|
$self->update( {
|
|
status => 'bounced',
|
|
errorMessage => $message,
|
|
bounceReason => $reason,
|
|
} );
|
|
|
|
#### TODO: Write to bounce log <= is this necessary? We're writing to the mail log already with most relevant info...
|
|
|
|
return;
|
|
}
|
|
|
|
1;
|
|
|