enotif should have a way to send bulk mail without customisations, for large sites
authorRiver Tarnell <river@users.mediawiki.org>
Sat, 5 May 2007 12:08:24 +0000 (12:08 +0000)
committerRiver Tarnell <river@users.mediawiki.org>
Sat, 5 May 2007 12:08:24 +0000 (12:08 +0000)
includes/DefaultSettings.php
includes/UserMailer.php
languages/messages/MessagesEn.php

index 7d38ede..90bb595 100644 (file)
@@ -1174,6 +1174,18 @@ $wgEnotifRevealEditorAddress     = false;        # UPO; reply-to address may be filled with
 $wgEnotifMinorEdits            = true; # UPO; false: "minor edits" on pages do not trigger notification mails.
 #                                                      # Attention: _every_ change on a user_talk page trigger a notification mail (if the user is not yet notified)
 
+# Send a generic mail instead of a personalised mail for each user.  This
+# always uses UTC as the time zone, and doesn't include the username.
+#
+# For pages with many users watching, this can significantly reduce mail load.
+# Has no effect when using sendmail rather than SMTP;
+
+$wgEnotifImpersonal = true;
+
+# Maximum number of users to mail at once when using impersonal mail.  Should 
+# match the limit on your mail server.
+$wgEnotifMaxRecips = 500;
+
 /** 
  * Array of usernames who will be sent a notification email for every change which occurs on a wiki
  */
index 9f5f178..eddedae 100644 (file)
@@ -72,6 +72,22 @@ class MailAddress {
        }
 }
 
+function send_mail($mailer, $dest, $headers, $body)
+{
+       $mailResult =& $mailer->send($dest, $headers, $body);
+
+       # Based on the result return an error string,
+       if ($mailResult === true) {
+               return '';
+       } elseif (is_object($mailResult)) {
+               wfDebug( "PEAR::Mail failed: " . $mailResult->getMessage() . "\n" );
+               return $mailResult->getMessage();
+       } else {
+               wfDebug( "PEAR::Mail failed, unknown error result\n" );
+               return 'Mail object return unknown error.';
+       }
+}
+
 /**
  * This function will perform a direct (authenticated) login to
  * a SMTP Server to use for mail relaying if 'wgSMTP' specifies an
@@ -85,16 +101,28 @@ class MailAddress {
  * @param $replyto String: optional reply-to email (default: null).
  */
 function userMailer( $to, $from, $subject, $body, $replyto=null ) {
-       global $wgUser, $wgSMTP, $wgOutputEncoding, $wgErrorString;
+       global $wgUser, $wgSMTP, $wgOutputEncoding, $wgErrorString, $wgEnotifImpersonal;
+       global $wgEnotifMaxRecips;
 
        if (is_array( $wgSMTP )) {
                require_once( 'Mail.php' );
 
                $timestamp = time();
-               $dest = $to->address;
+
+               if (is_array($to)) {
+                       $dest = array();
+                       foreach ($to as $u)
+                               $dest[] = $u->address;
+               } else
+                       $dest = $to->address;
 
                $headers['From'] = $from->toString();
-               $headers['To'] = $to->toString();
+
+               if ($wgEnotifImpersonal)
+                       $headers['To'] = 'undisclosed-recipients:;';
+               else
+                       $headers['To'] = $to->toString();
+
                if ( $replyto ) {
                        $headers['Reply-To'] = $replyto->toString();
                }
@@ -114,18 +142,16 @@ function userMailer( $to, $from, $subject, $body, $replyto=null ) {
                }
 
                wfDebug( "Sending mail via PEAR::Mail to $dest\n" );
-               $mailResult =& $mail_object->send($dest, $headers, $body);
-
-               # Based on the result return an error string,
-               if ($mailResult === true) {
-                       return '';
-               } elseif (is_object($mailResult)) {
-                       wfDebug( "PEAR::Mail failed: " . $mailResult->getMessage() . "\n" );
-                       return $mailResult->getMessage();
-               } else {
-                       wfDebug( "PEAR::Mail failed, unknown error result\n" );
-                       return 'Mail object return unknown error.';
-               }
+               if (is_array($dest)) {
+                       $chunks = array_chunk($dest, $wgEnotifMaxRecips);
+                       foreach ($chunks as $chunk) {
+                               $e = send_mail($mail_object, $dest, $headers, $body);
+                               if ($e != '')
+                                       return $e;
+                       }
+               } else
+                       return $mail_object->send($dest, $headers, $body);
+
        } else  {
                # In the following $headers = expression we removed "Reply-To: {$from}\r\n" , because it is treated differently
                # (fifth parameter of the PHP mail function, see some lines below)
@@ -217,6 +243,7 @@ class EmailNotification {
                # we use $wgEmergencyContact as sender's address
                global $wgUser, $wgEnotifWatchlist;
                global $wgEnotifMinorEdits, $wgEnotifUserTalk, $wgShowUpdatedMarker;
+               global $wgEnotifImpersonal;
 
                $fname = 'UserMailer::notifyOnPageChange';
                wfProfileIn( $fname );
@@ -236,6 +263,8 @@ class EmailNotification {
                $this->oldid = $oldid;
                $this->composeCommonMailtext();
 
+               $impersonals = array();
+
                if ( (!$minorEdit || $wgEnotifMinorEdits) ) {
                        if( $wgEnotifWatchlist ) {
                                // Send updates to watchers other than the current editor
@@ -287,7 +316,10 @@ class EmailNotification {
                                                && ($watchingUser->isEmailConfirmed() ) ) {
                                                        # ... adjust remaining text and page edit time placeholders
                                                        # which needs to be personalized for each user
-                                                       $this->composeAndSendPersonalisedMail( $watchingUser );
+                                                       if ($wgEnotifImpersonal)
+                                                               $impersonals[] = $watchingUser;
+                                                       else
+                                                               $this->composeAndSendPersonalisedMail( $watchingUser );
 
                                                } # if the watching user has an email address in the preferences
                                        }
@@ -298,9 +330,14 @@ class EmailNotification {
                global $wgUsersNotifedOnAllChanges;
                foreach ( $wgUsersNotifedOnAllChanges as $name ) {
                        $user = User::newFromName( $name );
-                       $this->composeAndSendPersonalisedMail( $user );
+                       if ($wgEnotifImpersonal)
+                               $impersonals[] = $user;
+                       else
+                               $this->composeAndSendPersonalisedMail( $user );
                }
 
+               $this->composeAndSendImpersonalMail($impersonals);
+
                if ( $wgShowUpdatedMarker || $wgEnotifWatchlist ) {
                        # mark the changed watch-listed page with a timestamp, so that the page is
                        # listed with an "updated since your last visit" icon in the watch list, ...
@@ -324,6 +361,7 @@ class EmailNotification {
        function composeCommonMailtext() {
                global $wgUser, $wgEmergencyContact, $wgNoReplyAddress;
                global $wgEnotifFromEditor, $wgEnotifRevealEditorAddress;
+               global $wgEnotifImpersonal;
 
                $summary = ($this->summary == '') ? ' - ' : $this->summary;
                $medit   = ($this->minorEdit) ? wfMsg( 'minoredit' ) : '';
@@ -353,6 +391,14 @@ class EmailNotification {
                        $keys['$CHANGEDORCREATED'] = wfMsgForContent( 'created' );
                }
 
+               if ($wgEnotifImpersonal && $this->oldid)
+                       /*
+                        * For impersonal mail, show a diff link to the last 
+                        * revision.
+                        */
+                       $keys['$NEWPAGE'] = wfMsgForContent('enotif_lastdiff',
+                                       $this->title->getFullURL("oldid={$this->oldid}&diff=prev"));
+
                $body = strtr( $body, $keys );
                $pagetitle = $this->title->getPrefixedText();
                $keys['$PAGETITLE']          = $pagetitle;
@@ -406,8 +452,6 @@ class EmailNotification {
                $this->body    = $body;
        }
 
-
-
        /**
         * Does the per-user customizations to a notification e-mail (name,
         * timestamp in proper timezone, etc) and sends it out.
@@ -439,5 +483,29 @@ class EmailNotification {
                return ($error == '');
        }
 
+       /**
+        * Same as composeAndSendPersonalisedMail but does impersonal mail 
+        * suitable for bulk mailing.  Takes an array of users.
+        */
+       function composeAndSendImpersonalMail($users) {
+               global $wgLang;
+
+               if (empty($users))
+                       return;
+
+               $to = array();
+               foreach ($users as $user)
+                       $to[] = new MailAddress($user);
+
+               $body = str_replace(
+                               array(  '$WATCHINGUSERNAME',
+                                       '$PAGEEDITDATE'),
+                               array(  wfMsgForContent('enotif_impersonal_salutation'),
+                                       $wgLang->timeanddate($this->timestamp, true, false, false)),
+                               $this->body);
+               $error = userMailer($to, $this->from, $this->subject, $body, $this->replyto);
+               return $error == '';
+       }
+
 } # end of class EmailNotification
 ?>
index 0373577..c774fa2 100644 (file)
@@ -1750,13 +1750,15 @@ at the bottom of the screen (deleting a content page also deletes the accompanyi
 'enotif_mailer'                => '{{SITENAME}} Notification Mailer',
 'enotif_reset'                 => 'Mark all pages visited',
 'enotif_newpagetext'=> 'This is a new page.',
+'enotif_impersonal_salutation' => '{{SITENAME}} user',
 'changed'                      => 'changed',
 'created'                      => 'created',
 'enotif_subject'       => '{{SITENAME}} page $PAGETITLE has been $CHANGEDORCREATED by $PAGEEDITOR',
 'enotif_lastvisited' => 'See $1 for all changes since your last visit.',
+'enotif_lastdiff' => 'See $1 to view this change.',
 'enotif_body' => 'Dear $WATCHINGUSERNAME,
 
-the {{SITENAME}} page $PAGETITLE has been $CHANGEDORCREATED on $PAGEEDITDATE by $PAGEEDITOR, see $PAGETITLE_URL for the current version.
+The {{SITENAME}} page $PAGETITLE has been $CHANGEDORCREATED on $PAGEEDITDATE by $PAGEEDITOR, see $PAGETITLE_URL for the current version.
 
 $NEWPAGE