From 03df01a7fad22e8ff4f9522f371ec808319f3263 Mon Sep 17 00:00:00 2001 From: River Tarnell Date: Sat, 5 May 2007 12:08:24 +0000 Subject: [PATCH] enotif should have a way to send bulk mail without customisations, for large sites --- includes/DefaultSettings.php | 12 ++++ includes/UserMailer.php | 106 ++++++++++++++++++++++++------ languages/messages/MessagesEn.php | 4 +- 3 files changed, 102 insertions(+), 20 deletions(-) diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 7d38ede63c..90bb595c5f 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -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 */ diff --git a/includes/UserMailer.php b/includes/UserMailer.php index 9f5f178c12..eddedae7b5 100644 --- a/includes/UserMailer.php +++ b/includes/UserMailer.php @@ -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 ?> diff --git a/languages/messages/MessagesEn.php b/languages/messages/MessagesEn.php index 0373577173..c774fa2ec5 100644 --- a/languages/messages/MessagesEn.php +++ b/languages/messages/MessagesEn.php @@ -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 -- 2.20.1