mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
API Moved email bounce handling to new 'emailbouncehandler' module
This commit is contained in:
parent
0f60ca7255
commit
5fed5b91c9
14
_config.php
14
_config.php
@ -34,18 +34,6 @@ define('MCE_ROOT', FRAMEWORK_DIR . '/thirdparty/tinymce/');
|
||||
ShortcodeParser::get('default')->register('file_link', array('File', 'link_shortcode_handler'));
|
||||
ShortcodeParser::get('default')->register('embed', array('Oembed', 'handle_shortcode'));
|
||||
|
||||
/**
|
||||
* The secret key that needs to be sent along with pings to /Email_BounceHandler
|
||||
*
|
||||
* Change this to something different for increase security (you can
|
||||
* override it in mysite/_config.php to ease upgrades).
|
||||
* For more information see:
|
||||
* {@link http://doc.silverstripe.org/doku.php?id=email_bouncehandler}
|
||||
*/
|
||||
if(!defined('EMAIL_BOUNCEHANDLER_KEY')) {
|
||||
define('EMAIL_BOUNCEHANDLER_KEY', '1aaaf8fb60ea253dbf6efa71baaacbb3');
|
||||
}
|
||||
|
||||
// Zend_Cache temp directory setting
|
||||
$_ENV['TMPDIR'] = TEMP_FOLDER; // for *nix
|
||||
$_ENV['TMP'] = TEMP_FOLDER; // for Windows
|
||||
@ -60,4 +48,4 @@ SS_Cache::pick_backend('aggregatestore', 'aggregate', 1000);
|
||||
Deprecation::notification_version('3.0.0');
|
||||
|
||||
// TODO Remove once new ManifestBuilder with submodule support is in place
|
||||
require_once('admin/_config.php');
|
||||
require_once('admin/_config.php');
|
@ -14,6 +14,10 @@
|
||||
* Removed `Member_ProfileForm`, use `CMSProfileController` instead
|
||||
* `SiteTree::$nested_urls` enabled by default. To disable, call `SiteTree::disable_nested_urls()`.
|
||||
* Removed CMS permission checks from `File->canEdit()` and `File->canDelete()`. If you have unsecured controllers relying on these permissions, please override them through a `DataExtension`.
|
||||
* Moved email bounce handling to new ["emailbouncehandler" module](https://github.com/silverstripe-labs/silverstripe-emailbouncehandler),
|
||||
including `Email_BounceHandler` and `Email_BounceRecord` classes,
|
||||
as well as the `Member->Bounced` property.
|
||||
* Deprecated global email methods `htmlEmail()` and `plaintextEmail`, as well as various email helper methods like `encodeMultipart()`. Use the `Email` API, or the `Mailer` class where applicable.
|
||||
* Removed non-functional `$inlineImages` option for sending emails * Removed support for keyed arrays in `SelectionGroup`, use new `SelectionGroup_Item` object
|
||||
* Removed non-functional `$inlineImages` option for sending emails
|
||||
* Removed support for keyed arrays in `SelectionGroup`, use new `SelectionGroup_Item` object
|
||||
to populate the list instead (see [API docs](api:SelectionGroup)).
|
193
email/Email.php
193
email/Email.php
@ -16,8 +16,6 @@ if(isset($_SERVER['SERVER_NAME'])) {
|
||||
*/
|
||||
define('X_MAILER', 'SilverStripe Mailer - version 2006.06.21');
|
||||
}
|
||||
// Note: The constant 'BOUNCE_EMAIL' should be defined as a valid email address for where bounces should be returned
|
||||
// to.
|
||||
|
||||
/**
|
||||
* Class to support sending emails.
|
||||
@ -113,11 +111,6 @@ class Email extends ViewableData {
|
||||
*/
|
||||
protected $template_data = null;
|
||||
|
||||
/**
|
||||
* @param string $bounceHandlerURL
|
||||
*/
|
||||
protected $bounceHandlerURL = null;
|
||||
|
||||
/**
|
||||
* @param sring $admin_email_address The default administrator email address.
|
||||
* This will be set in the config on a site-by-site basis
|
||||
@ -151,7 +144,11 @@ class Email extends ViewableData {
|
||||
if($body != null) $this->body = $body;
|
||||
if($cc != null) $this->cc = $cc;
|
||||
if($bcc != null) $this->bcc = $bcc;
|
||||
if($bounceHandlerURL != null) $this->setBounceHandlerURL($bounceHandlerURL);
|
||||
|
||||
if($bounceHandlerURL != null) {
|
||||
Deprecation::notice('3.1', 'Use "emailbouncehandler" module');
|
||||
}
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
@ -163,12 +160,8 @@ class Email extends ViewableData {
|
||||
);
|
||||
}
|
||||
|
||||
public function setBounceHandlerURL( $bounceHandlerURL ) {
|
||||
if($bounceHandlerURL) {
|
||||
$this->bounceHandlerURL = $bounceHandlerURL;
|
||||
} else {
|
||||
$this->bounceHandlerURL = $_SERVER['HTTP_HOST'] . Director::baseURL() . 'Email_BounceHandler';
|
||||
}
|
||||
public function setBounceHandlerURL($bounceHandlerURL) {
|
||||
Deprecation::notice('3.1', 'Use "emailbouncehandler" module');
|
||||
}
|
||||
|
||||
public function attachFile($filename, $attachedFilename = null, $mimetype = null) {
|
||||
@ -388,12 +381,8 @@ class Email extends ViewableData {
|
||||
|
||||
if(empty($this->from)) $this->from = Email::getAdminEmail();
|
||||
|
||||
$this->setBounceHandlerURL($this->bounceHandlerURL);
|
||||
|
||||
$headers = $this->customHeaders;
|
||||
|
||||
$headers['X-SilverStripeBounceURL'] = $this->bounceHandlerURL;
|
||||
|
||||
if($messageID) $headers['X-SilverStripeMessageID'] = project() . '.' . $messageID;
|
||||
|
||||
if(project()) $headers['X-SilverStripeSite'] = project();
|
||||
@ -449,12 +438,8 @@ class Email extends ViewableData {
|
||||
|
||||
if(empty($this->from)) $this->from = Email::getAdminEmail();
|
||||
|
||||
$this->setBounceHandlerURL( $this->bounceHandlerURL );
|
||||
|
||||
$headers = $this->customHeaders;
|
||||
|
||||
$headers['X-SilverStripeBounceURL'] = $this->bounceHandlerURL;
|
||||
|
||||
if($messageID) $headers['X-SilverStripeMessageID'] = project() . '.' . $messageID;
|
||||
|
||||
if(project()) $headers['X-SilverStripeSite'] = project();
|
||||
@ -620,167 +605,3 @@ class Email extends ViewableData {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class that email bounce handlers extend
|
||||
* @package framework
|
||||
* @subpackage email
|
||||
*/
|
||||
class Email_BounceHandler extends Controller {
|
||||
|
||||
static $allowed_actions = array(
|
||||
'index'
|
||||
);
|
||||
|
||||
public function init() {
|
||||
BasicAuth::protect_entire_site(false);
|
||||
parent::init();
|
||||
}
|
||||
|
||||
public function index() {
|
||||
$subclasses = ClassInfo::subclassesFor( $this->class );
|
||||
unset($subclasses[$this->class]);
|
||||
|
||||
if( $subclasses ) {
|
||||
$subclass = array_pop( $subclasses );
|
||||
$task = new $subclass();
|
||||
$task->index();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if access key exists
|
||||
if( !isset($_REQUEST['Key']) ) {
|
||||
echo 'Error: Access validation failed. No "Key" specified.';
|
||||
return;
|
||||
}
|
||||
|
||||
// Check against access key defined in framework/_config.php
|
||||
if( $_REQUEST['Key'] != EMAIL_BOUNCEHANDLER_KEY) {
|
||||
echo 'Error: Access validation failed. Invalid "Key" specified.';
|
||||
return;
|
||||
}
|
||||
|
||||
if( !$_REQUEST['Email'] ) {
|
||||
echo "No email address";
|
||||
return;
|
||||
}
|
||||
|
||||
$this->recordBounce( $_REQUEST['Email'], $_REQUEST['Date'], $_REQUEST['Time'], $_REQUEST['Message'] );
|
||||
}
|
||||
|
||||
private function recordBounce( $email, $date = null, $time = null, $error = null ) {
|
||||
if(preg_match('/<(.*)>/', $email, $parts)) $email = $parts[1];
|
||||
|
||||
$SQL_email = Convert::raw2sql($email);
|
||||
$SQL_bounceTime = Convert::raw2sql("$date $time");
|
||||
|
||||
$duplicateBounce = DataObject::get_one("Email_BounceRecord",
|
||||
"\"BounceEmail\" = '$SQL_email' AND (\"BounceTime\"+INTERVAL 1 MINUTE) > '$SQL_bounceTime'");
|
||||
|
||||
if(!$duplicateBounce) {
|
||||
$record = new Email_BounceRecord();
|
||||
|
||||
$member = DataObject::get_one( 'Member', "\"Email\"='$SQL_email'" );
|
||||
|
||||
if( $member ) {
|
||||
$record->MemberID = $member->ID;
|
||||
|
||||
// If the SilverStripeMessageID (taken from the X-SilverStripeMessageID header embedded in the email)
|
||||
// is sent, then log this bounce in a Newsletter_SentRecipient record so it will show up on the 'Sent
|
||||
// Status Report' tab of the Newsletter
|
||||
if( isset($_REQUEST['SilverStripeMessageID'])) {
|
||||
// Note: was sent out with: $project . '.' . $messageID;
|
||||
$message_id_parts = explode('.', $_REQUEST['SilverStripeMessageID']);
|
||||
// Note: was encoded with: base64_encode( $newsletter->ID . '_' . date( 'd-m-Y H:i:s' ) );
|
||||
$newsletter_id_date_parts = explode ('_', base64_decode($message_id_parts[1]) );
|
||||
|
||||
// Escape just in case
|
||||
$SQL_memberID = Convert::raw2sql($member->ID);
|
||||
$SQL_newsletterID = Convert::raw2sql($newsletter_id_date_parts[0]);
|
||||
|
||||
// Log the bounce
|
||||
$oldNewsletterSentRecipient = DataObject::get_one("Newsletter_SentRecipient",
|
||||
"\"MemberID\" = '$SQL_memberID' AND \"ParentID\" = '$SQL_newsletterID'"
|
||||
. " AND \"Email\" = '$SQL_email'");
|
||||
|
||||
// Update the Newsletter_SentRecipient record if it exists
|
||||
if($oldNewsletterSentRecipient) {
|
||||
$oldNewsletterSentRecipient->Result = 'Bounced';
|
||||
$oldNewsletterSentRecipient->write();
|
||||
} else {
|
||||
// For some reason it didn't exist, create a new record
|
||||
$newNewsletterSentRecipient = new Newsletter_SentRecipient();
|
||||
$newNewsletterSentRecipient->Email = $SQL_email;
|
||||
$newNewsletterSentRecipient->MemberID = $member->ID;
|
||||
$newNewsletterSentRecipient->Result = 'Bounced';
|
||||
$newNewsletterSentRecipient->ParentID = $newsletter_id_date_parts[0];
|
||||
$newNewsletterSentRecipient->write();
|
||||
}
|
||||
|
||||
// Now we are going to Blacklist this member so that email will not be sent to them in the future.
|
||||
// Note: Sending can be re-enabled by going to 'Mailing List' 'Bounced' tab and unchecking the box
|
||||
// under 'Blacklisted'
|
||||
$member->setBlacklistedEmail(TRUE);
|
||||
echo '<p><b>Member: '.$member->FirstName.' '.$member->Surname
|
||||
.' <'.$member->Email.'> was added to the Email Blacklist!</b></p>';
|
||||
}
|
||||
}
|
||||
|
||||
if( !$date )
|
||||
$date = date( 'd-m-Y' );
|
||||
/*else
|
||||
$date = date( 'd-m-Y', strtotime( $date ) );*/
|
||||
|
||||
if( !$time )
|
||||
$time = date( 'H:i:s' );
|
||||
/*else
|
||||
$time = date( 'H:i:s', strtotime( $time ) );*/
|
||||
|
||||
$record->BounceEmail = $email;
|
||||
$record->BounceTime = $date . ' ' . $time;
|
||||
$record->BounceMessage = $error;
|
||||
$record->write();
|
||||
|
||||
echo "Handled bounced email to address: $email";
|
||||
} else {
|
||||
echo 'Sorry, this bounce report has already been logged, not logging this duplicate bounce.';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Database record for recording a bounced email
|
||||
* @package framework
|
||||
* @subpackage email
|
||||
*/
|
||||
class Email_BounceRecord extends DataObject {
|
||||
static $db = array(
|
||||
'BounceEmail' => 'Varchar',
|
||||
'BounceTime' => 'SS_Datetime',
|
||||
'BounceMessage' => 'Varchar'
|
||||
);
|
||||
|
||||
static $has_one = array(
|
||||
'Member' => 'Member'
|
||||
);
|
||||
|
||||
static $has_many = array();
|
||||
|
||||
static $many_many = array();
|
||||
|
||||
static $defaults = array();
|
||||
|
||||
static $singular_name = 'Email Bounce Record';
|
||||
|
||||
|
||||
/**
|
||||
* a record of Email_BounceRecord can't be created manually. Instead, it should be
|
||||
* created though system.
|
||||
*/
|
||||
public function canCreate($member = null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -15,7 +15,6 @@ class Member extends DataObject implements TemplateGlobalProvider {
|
||||
'RememberLoginToken' => 'Varchar(160)', // Note: this currently holds a hash, not a token.
|
||||
'NumVisit' => 'Int',
|
||||
'LastVisited' => 'SS_Datetime',
|
||||
'Bounced' => 'Boolean', // Note: This does not seem to be used anywhere.
|
||||
'AutoLoginHash' => 'Varchar(160)',
|
||||
'AutoLoginExpired' => 'SS_Datetime',
|
||||
// This is an arbitrary code pointing to a PasswordEncryptor instance,
|
||||
@ -584,7 +583,6 @@ class Member extends DataObject implements TemplateGlobalProvider {
|
||||
$fields->removeByName('RememberLoginToken');
|
||||
$fields->removeByName('NumVisit');
|
||||
$fields->removeByName('LastVisited');
|
||||
$fields->removeByName('Bounced');
|
||||
$fields->removeByName('AutoLoginHash');
|
||||
$fields->removeByName('AutoLoginExpired');
|
||||
$fields->removeByName('PasswordEncryption');
|
||||
@ -1197,7 +1195,6 @@ class Member extends DataObject implements TemplateGlobalProvider {
|
||||
i18n::get_existing_translations()
|
||||
));
|
||||
|
||||
$mainFields->removeByName('Bounced');
|
||||
$mainFields->removeByName('RememberLoginToken');
|
||||
$mainFields->removeByName('AutoLoginHash');
|
||||
$mainFields->removeByName('AutoLoginExpired');
|
||||
|
Loading…
x
Reference in New Issue
Block a user