return true;
}
+/**
+ * Generate a unique email Message-ID using the moodle domain and install path
+ *
+ * @param string $localpart An optional unique message id prefix.
+ * @return string The formatted ID ready for appending to the email headers.
+ */
+function generate_email_messageid($localpart = null) {
+ global $CFG;
+
+ $urlinfo = parse_url($CFG->wwwroot);
+ $base = '@' . $urlinfo['host'];
+
+ // If multiple moodles are on the same domain we want to tell them
+ // apart so we add the install path to the local part. This means
+ // that the id local part should never contain a / character so
+ // we can correctly parse the id to reassemble the wwwroot.
+ if (isset($urlinfo['path'])) {
+ $base = $urlinfo['path'] . $base;
+ }
+
+ if (empty($localpart)) {
+ $localpart = uniqid('', true);
+ }
+
+ // Because we may have an option /installpath suffix to the local part
+ // of the id we need to escape any / chars which are in the $localpart.
+ $localpart = str_replace('/', '%2F', $localpart);
+
+ return '<' . $localpart . $base . '>';
+}
+
/**
* Send an email to a specified user
*
$mail->FromName = $renderer->render_from_template('core/email_fromname', $context);
$messagetext = $renderer->render_from_template('core/email_text', $context);
+ // Autogenerate a MessageID if it's missing.
+ if (empty($mail->MessageID)) {
+ $mail->MessageID = generate_email_messageid();
+ }
+
if ($messagehtml && !empty($user->mailformat) && $user->mailformat == 1) {
// Don't ever send HTML to users who don't want it.
$mail->isHTML(true);
$this->assertEventContextNotUsed($event);
}
+ /**
+ * A data provider for testing email messageid
+ */
+ public function generate_email_messageid_provider() {
+ return array(
+ 'nopath' => array(
+ 'wwwroot' => 'http://www.example.com',
+ 'ids' => array(
+ 'a-custom-id' => '<a-custom-id@www.example.com>',
+ 'an-id-with-/-a-slash' => '<an-id-with-%2F-a-slash@www.example.com>',
+ ),
+ ),
+ 'path' => array(
+ 'wwwroot' => 'http://www.example.com/path/subdir',
+ 'ids' => array(
+ 'a-custom-id' => '<a-custom-id/path/subdir@www.example.com>',
+ 'an-id-with-/-a-slash' => '<an-id-with-%2F-a-slash/path/subdir@www.example.com>',
+ ),
+ ),
+ );
+ }
+
+ /**
+ * Test email message id generation
+ *
+ * @dataProvider generate_email_messageid_provider
+ *
+ * @param string $wwwroot The wwwroot
+ * @param array $msgids An array of msgid local parts and the final result
+ */
+ public function test_generate_email_messageid($wwwroot, $msgids) {
+ global $CFG;
+
+ $this->resetAfterTest();
+ $CFG->wwwroot = $wwwroot;
+
+ foreach ($msgids as $local => $final) {
+ $this->assertEquals($final, generate_email_messageid($local));
+ }
+ }
+ /**
+ * A data provider for testing email diversion
+ */
public function diverted_emails_provider() {
return array(
'nodiverts' => array(
}
/**
+ * Test email diversion
+ *
* @dataProvider diverted_emails_provider
+ *
+ * @param string $divertallemailsto An optional email address
+ * @param string $divertallemailsexcept An optional exclusion list
+ * @param array $addresses An array of test addresses
+ * @param boolean $expected Expected result
*/
public function test_email_should_be_diverted($divertallemailsto, $divertallemailsexcept, $addresses, $expected) {
global $CFG;
*
* @param int $postid The ID of the forum post we are notifying the user about
* @param int $usertoid The ID of the user being notified
- * @param string $hostname The server's hostname
* @return string A unique message-id
*/
-function forum_get_email_message_id($postid, $usertoid, $hostname) {
- return '<'.hash('sha256',$postid.'to'.$usertoid).'@'.$hostname.'>';
+function forum_get_email_message_id($postid, $usertoid) {
+ return generate_email_messageid(hash('sha256', $postid . 'to' . $usertoid));
}
/**
if ($users && $posts) {
- $urlinfo = parse_url($CFG->wwwroot);
- $hostname = $urlinfo['host'];
-
foreach ($users as $userto) {
// Terminate if processing of any account takes longer than 2 minutes.
core_php_time_limit::raise(120);
$userfrom->customheaders = array (
// Headers to make emails easier to track.
- 'List-Id: "' . $cleanforumname . '" <moodleforum' . $forum->id . '@' . $hostname.'>',
+ 'List-Id: "' . $cleanforumname . '" ' . generate_email_messageid('moodleforum' . $forum->id),
'List-Help: ' . $CFG->wwwroot . '/mod/forum/view.php?f=' . $forum->id,
- 'Message-ID: ' . forum_get_email_message_id($post->id, $userto->id, $hostname),
+ 'Message-ID: ' . forum_get_email_message_id($post->id, $userto->id),
'X-Course-Id: ' . $course->id,
'X-Course-Name: ' . format_string($course->fullname, true),
$a->courseshortname = $data->get_coursename();
$postsubject = html_to_text(get_string('postmailsubject', 'forum', $a), 0);
- $rootid = forum_get_email_message_id($discussion->firstpost, $userto->id, $hostname);
+ $rootid = forum_get_email_message_id($discussion->firstpost, $userto->id);
if ($post->parent) {
// This post is a reply, so add reply header (RFC 2822).
- $parentid = forum_get_email_message_id($post->parent, $userto->id, $hostname);
+ $parentid = forum_get_email_message_id($post->parent, $userto->id);
$userfrom->customheaders[] = "In-Reply-To: $parentid";
// If the post is deeply nested we also reference the parent message id and
This files describes API changes in /mod/forum/*,
information provided here is intended especially for developers.
+=== 3.1 ===
+ * The inteface to forum_get_email_message_id() has changed and no longer needs the $host argument.
+
=== 3.0 ===
* External function get_forums_by_courses now returns and additional field "cancreatediscussions" that indicates if the user
can create discussions in the forum.