Permalink
Browse files

API Moved email bounce handling to new 'emailbouncehandler' module

  • Loading branch information...
1 parent 0f60ca7 commit 5fed5b91c996514d44297db45b58474e379c9b7b @chillu chillu committed Dec 3, 2012
Showing with 13 additions and 203 deletions.
  1. +1 −13 _config.php
  2. +5 −1 docs/en/changelogs/3.1.0.md
  3. +7 −186 email/Email.php
  4. +0 −3 security/Member.php
View
@@ -34,18 +34,6 @@
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 @@
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)).
View
@@ -16,8 +16,6 @@
*/
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.
@@ -114,11 +112,6 @@ public static function mailer() {
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 @@ public function __construct($from = null, $to = null, $subject = null, $body = n
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 @@ public function attachFileFromString($data, $filename, $mimetype = null) {
);
}
- 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 @@ public function sendPlain($messageID = null) {
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 @@ public function send($messageID = null) {
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 @@ public static function obfuscate($email, $method = 'visible') {
}
}
}
-
-/**
- * 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;
- }
-}
-
-
View
@@ -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 @@ public function getMemberFormFields() {
$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 @@ public function getCMSFields() {
i18n::get_existing_translations()
));
- $mainFields->removeByName('Bounced');
$mainFields->removeByName('RememberLoginToken');
$mainFields->removeByName('AutoLoginHash');
$mainFields->removeByName('AutoLoginExpired');

0 comments on commit 5fed5b9

Please sign in to comment.