diff --git a/admin/cron.php b/admin/cron.php index 21e6ca94056..58d4cc0b1ef 100644 --- a/admin/cron.php +++ b/admin/cron.php @@ -100,6 +100,7 @@ /// Run all cron jobs for each module mtrace("Starting activity modules"); + get_mailer('buffer'); if ($mods = get_records_select("modules", "cron > 0 AND (($timenow - lastcron) > cron)")) { foreach ($mods as $mod) { $libfile = "$CFG->dirroot/mod/$mod->name/lib.php"; @@ -128,6 +129,7 @@ } } } + get_mailer('close'); mtrace("Finished activity modules"); mtrace("Starting blocks"); diff --git a/admin/settings/server.php b/admin/settings/server.php index 029385d895e..6fc9d2a53d1 100644 --- a/admin/settings/server.php +++ b/admin/settings/server.php @@ -23,6 +23,7 @@ $temp = new admin_settingpage('mail', get_string('mail','admin')); $temp->add(new admin_setting_configtext('smtphosts', get_string('smtphosts', 'admin'), get_string('configsmtphosts', 'admin'), '', PARAM_HOST)); $temp->add(new admin_setting_configtext('smtpuser', get_string('smtpuser', 'admin'), get_string('configsmtpuser', 'admin'), '', PARAM_NOTAGS)); $temp->add(new admin_setting_configpasswordunmask('smtppass', get_string('smtppass', 'admin'), get_string('configsmtpuser', 'admin'), '')); +$temp->add(new admin_setting_configtext('smtpmaxbulk', get_string('smtpmaxbulk', 'admin'), get_string('configsmtpmaxbulk', 'admin'), 0, PARAM_INT)); $temp->add(new admin_setting_configtext('noreplyaddress', get_string('noreplyaddress', 'admin'), get_string('confignoreplyaddress', 'admin'), 'noreply@' . $_SERVER['HTTP_HOST'], PARAM_NOTAGS)); $temp->add(new admin_setting_configselect('digestmailtime', get_string('digestmailtime', 'admin'), get_string('configdigestmailtime', 'admin'), 17, array('00' => '00', '01' => '01', diff --git a/lang/en_utf8/admin.php b/lang/en_utf8/admin.php index 28450b74070..195ad0140b1 100644 --- a/lang/en_utf8/admin.php +++ b/lang/en_utf8/admin.php @@ -213,6 +213,7 @@ $string['configsitemailcharset'] = 'All the emails generated by your site will b $string['configsitepolicy'] = 'If you have a site policy that all users must see and agree to before using this site, then specify the URL to it here, otherwise leave this field blank. The URL can point to anywhere - one convenient place would be a file in the site files. eg http://yoursite/file.php/1/policy.html'; $string['configslasharguments'] = 'Files (images, uploads etc) are provided via a script using \'slash arguments\'. This method allows files to be more easily cached in web browsers, proxy servers etc. Unfortunately, some PHP servers don\'t allow this method, so if you have trouble viewing uploaded files or images (eg user pictures), disable this setting.'; $string['configsmartpix'] = 'With this on, icons are served through a PHP script that searches the current theme, then all parent themes, then the Moodle /pix folder. This reduces the need to duplicate image files within themes, but has a slight performance cost.'; +$string['configsmtpmaxbulk'] = 'Send multiple messages in one SMTP session, this may speed up sending of emails.'; $string['configsmtphosts'] = 'Give the full name of one or more local SMTP servers that Moodle should use to send mail (eg \'mail.a.com\' or \'mail.a.com;mail.b.com\'). If you leave it blank, Moodle will use the PHP default method of sending mail.'; $string['configsmtpuser'] = 'If you have specified an SMTP server above, and the server requires authentication, then enter the username and password here.'; $string['configstartwday'] = 'Start of Week'; @@ -626,6 +627,7 @@ $string['sitesectionhelp'] = 'If selected, a topic section will be displayed on $string['slasharguments'] = 'Use slash arguments'; $string['smartpix'] ='Smart pix search'; $string['smtphosts'] = 'SMTP hosts'; +$string['smtpmaxbulk'] = 'SMTP bulk sending'; $string['smtppass'] = 'SMTP password'; $string['smtpuser'] = 'SMTP username'; $string['stats'] = 'Statistics'; diff --git a/lib/moodlelib.php b/lib/moodlelib.php index 6415a36f7b7..71d0b39cf69 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -3787,6 +3787,131 @@ function moodle_process_email($modargs,$body) { /// CORRESPONDENCE //////////////////////////////////////////////// +/** + * Get mailer instance, enable buffering, flush buffer or disable buffering. + * @param $action string 'get', 'buffer', 'close' or 'flush' + * @return reference to mailer instance if 'get' used or nothing + */ +function &get_mailer($action='get') { + global $CFG; + + static $mailer = null; + static $counter = 0; + + if (!isset($CFG->smtpmaxbulk)) { + $CFG->smtpmaxbulk = 0; + } + + if ($action == 'get') { + $prevkeepalive = false; + + if (isset($mailer) and $mailer->Mailer == 'smtp') { + if ($counter < $CFG->smtpmaxbulk and empty($mailer->error_count)) { + $counter++; + // reset the mailer + $mailer->Priority = 3; + $mailer->CharSet = 'UTF-8'; // our default + $mailer->ContentType = "text/plain"; + $mailer->Encoding = "8bit"; + $mailer->From = "root@localhost"; + $mailer->FromName = "Root User"; + $mailer->Sender = ""; + $mailer->Subject = ""; + $mailer->Body = ""; + $mailer->AltBody = ""; + $mailer->ConfirmReadingTo = ""; + + $mailer->ClearAllRecipients(); + $mailer->ClearReplyTos(); + $mailer->ClearAttachments(); + $mailer->ClearCustomHeaders(); + return $mailer; + } + + $prevkeepalive = $mailer->SMTPKeepAlive; + get_mailer('flush'); + } + + include_once($CFG->libdir.'/phpmailer/class.phpmailer.php'); + $mailer = new phpmailer(); + + $counter = 0; + + $mailer->Version = 'Moodle '.$CFG->version; // mailer version + $mailer->PluginDir = $CFG->libdir.'/phpmailer/'; // plugin directory (eg smtp plugin) + $mailer->CharSet = 'UTF-8'; + + // some MTAs may do double conversion of LF if CRLF used, CRLF is required line ending in RFC 822bis + // hmm, this is a bit hacky because LE should be private + if (isset($CFG->mailnewline) and $CFG->mailnewline == 'CRLF') { + $mailer->LE = "\r\n"; + } else { + $mailer->LE = "\n"; + } + + if ($CFG->smtphosts == 'qmail') { + $mailer->IsQmail(); // use Qmail system + + } else if (empty($CFG->smtphosts)) { + $mailer->IsMail(); // use PHP mail() = sendmail + + } else { + $mailer->IsSMTP(); // use SMTP directly + if (!empty($CFG->debugsmtp)) { + $mailer->SMTPDebug = true; + } + $mailer->Host = $CFG->smtphosts; // specify main and backup servers + $mailer->SMTPKeepAlive = $prevkeepalive; // use previous keepalive + + if ($CFG->smtpuser) { // Use SMTP authentication + $mailer->SMTPAuth = true; + $mailer->Username = $CFG->smtpuser; + $mailer->Password = $CFG->smtppass; + } + } + + return $mailer; + } + + $nothing = null; + + // keep smtp session open after sending + if ($action == 'buffer') { + if (!empty($CFG->smtpmaxbulk)) { + get_mailer('flush'); + $m =& get_mailer(); + if ($m->Mailer == 'smtp') { + $m->SMTPKeepAlive = true; + } + } + return $nothing; + } + + // close smtp session, but continue buffering + if ($action == 'flush') { + if (isset($mailer) and $mailer->Mailer == 'smtp') { + if (!empty($mailer->SMTPDebug)) { + echo '
'."\n"; + } + $mailer->SmtpClose(); + if (!empty($mailer->SMTPDebug)) { + echo ''; + } + } + return $nothing; + } + + // close smtp session, do not buffer anymore + if ($action == 'close') { + if (isset($mailer) and $mailer->Mailer == 'smtp') { + get_mailer('flush'); + $mailer->SMTPKeepAlive = false; + } + $mailer = null; // better force new instance + return $nothing; + } +} + /** * Send an email to a specified user * @@ -3809,10 +3934,6 @@ function email_to_user($user, $from, $subject, $messagetext, $messagehtml='', $a global $CFG, $FULLME; - include_once($CFG->libdir .'/phpmailer/class.phpmailer.php'); - -/// We are going to use textlib services here - $textlib = textlib_get_instance(); if (empty($user)) { return false; @@ -3832,51 +3953,23 @@ function email_to_user($user, $from, $subject, $messagetext, $messagehtml='', $a return false; } - $mail = new phpmailer; + $mail =& get_mailer(); - $mail->Version = 'Moodle '. $CFG->version; // mailer version - $mail->PluginDir = $CFG->libdir .'/phpmailer/'; // plugin directory (eg smtp plugin) - - $mail->CharSet = 'UTF-8'; - - // some MTAs may do double conversion of LF if CRLF used, CRLF is required line ending in RFC 822bis - // hmm, this is a bit hacky because LE should be private - if (isset($CFG->mailnewline) and $CFG->mailnewline == 'CRLF') { - $mail->LE = "\r\n"; - } else { - $mail->LE = "\n"; + if (!empty($mail->SMTPDebug)) { + echo '
' . "\n"; } - if ($CFG->smtphosts == 'qmail') { - $mail->IsQmail(); // use Qmail system - - } else if (empty($CFG->smtphosts)) { - $mail->IsMail(); // use PHP mail() = sendmail - - } else { - $mail->IsSMTP(); // use SMTP directly - if (!empty($CFG->debugsmtp)) { - echo ''; } return false;' . "\n"; - $mail->SMTPDebug = true; - } - $mail->Host = $CFG->smtphosts; // specify main and backup servers - - if ($CFG->smtpuser) { // Use SMTP authentication - $mail->SMTPAuth = true; - $mail->Username = $CFG->smtpuser; - $mail->Password = $CFG->smtppass; - } - } +/// We are going to use textlib services here + $textlib = textlib_get_instance(); $supportuser = generate_email_supportuser(); - // make up an email address for handling bounces if (!empty($CFG->handlebounces)) { $modargs = 'B'.base64_encode(pack('V',$user->id)).substr(md5($user->email),0,16); $mail->Sender = generate_email_processing_address(0,$modargs); } else { - $mail->Sender = $supportuser->email; + $mail->Sender = $supportuser->email; } if (is_string($from)) { // So we can pass whatever we want if there is need @@ -3974,14 +4067,14 @@ function email_to_user($user, $from, $subject, $messagetext, $messagehtml='', $a if ($mail->Send()) { set_send_count($user); $mail->IsSMTP(); // use SMTP directly - if (!empty($CFG->debugsmtp)) { + if (!empty($mail->SMTPDebug)) { echo ''; } return true; } else { mtrace('ERROR: '. $mail->ErrorInfo); add_to_log(SITEID, 'library', 'mailer', $FULLME, 'ERROR: '. $mail->ErrorInfo); - if (!empty($CFG->debugsmtp)) { + if (!empty($mail->SMTPDebug)) { echo '