/** * Send an email to a specified user * * @param stdClass $user A {@link $USER} object * @param stdClass $from A {@link $USER} object * @param string $subject plain text subject line of the email * @param string $messagetext plain text version of the message * @param string $messagehtml complete html version of the message (optional) * @param string $attachment a file on the filesystem, either relative to $CFG->dataroot or a full path to a file in $CFG->tempdir * @param string $attachname the name of the file (extension indicates MIME) * @param bool $usetrueaddress determines whether $from email address should * be sent out. Will be overruled by user profile setting for maildisplay * @param string $replyto Email address to reply to * @param string $replytoname Name of reply to recipient * @param int $wordwrapwidth custom word wrap width, default 79 * @return bool Returns true if mail was sent OK and false if there was an error. */ function email_to_user($user, $from, $subject, $messagetext, $messagehtml = '', $attachment = '', $attachname = '', $usetrueaddress = true, $replyto = '', $replytoname = '', $wordwrapwidth = 79) { global $CFG; if (empty($user) or empty($user->id)) { debugging('Can not send email to null user', DEBUG_DEVELOPER); return false; } if (empty($user->email)) { debugging('Can not send email to user without email: ' . $user->id, DEBUG_DEVELOPER); return false; } if (!empty($user->deleted)) { debugging('Can not send email to deleted user: '******'BEHAT_SITE_RUNNING')) { // Fake email sending in behat. return true; } if (!empty($CFG->noemailever)) { // Hidden setting for development sites, set in config.php if needed. debugging('Not sending email due to $CFG->noemailever config setting', DEBUG_NORMAL); return true; } if (!empty($CFG->divertallemailsto)) { $subject = "[DIVERTED {$user->email}] {$subject}"; $user = clone $user; $user->email = $CFG->divertallemailsto; } // Skip mail to suspended users. if (isset($user->auth) && $user->auth == 'nologin' or isset($user->suspended) && $user->suspended) { return true; } if (!validate_email($user->email)) { // We can not send emails to invalid addresses - it might create security issue or confuse the mailer. debugging("email_to_user: User {$user->id} (" . fullname($user) . ") email ({$user->email}) is invalid! Not sending."); return false; } if (over_bounce_threshold($user)) { debugging("email_to_user: User {$user->id} (" . fullname($user) . ") is over bounce threshold! Not sending."); return false; } // TLD .invalid is specifically reserved for invalid domain names. // For More information, see {@link http://tools.ietf.org/html/rfc2606#section-2}. if (substr($user->email, -8) == '.invalid') { debugging("email_to_user: User {$user->id} (" . fullname($user) . ") email domain ({$user->email}) is invalid! Not sending."); return true; // This is not an error. } // If the user is a remote mnet user, parse the email text for URL to the // wwwroot and modify the url to direct the user's browser to login at their // home site (identity provider - idp) before hitting the link itself. if (is_mnet_remote_user($user)) { require_once $CFG->dirroot . '/mnet/lib.php'; $jumpurl = mnet_get_idp_jump_url($user); $callback = partial('mnet_sso_apply_indirection', $jumpurl); $messagetext = preg_replace_callback("%({$CFG->wwwroot}[^[:space:]]*)%", $callback, $messagetext); $messagehtml = preg_replace_callback("%href=[\"'`]({$CFG->wwwroot}[\\w_:\\?=#&@/;.~-]*)[\"'`]%", $callback, $messagehtml); } $mail = get_mailer(); if (!empty($mail->SMTPDebug)) { echo '<pre>' . "\n"; } $temprecipients = array(); $tempreplyto = array(); $supportuser = core_user::get_support_user(); // 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; } if (!empty($CFG->emailonlyfromnoreplyaddress)) { $usetrueaddress = false; if (empty($replyto) && $from->maildisplay) { $replyto = $from->email; $replytoname = fullname($from); } } if (is_string($from)) { // So we can pass whatever we want if there is need. $mail->From = $CFG->noreplyaddress; $mail->FromName = $from; } else { if ($usetrueaddress and $from->maildisplay) { $mail->From = $from->email; $mail->FromName = fullname($from); } else { $mail->From = $CFG->noreplyaddress; $mail->FromName = fullname($from); if (empty($replyto)) { $tempreplyto[] = array($CFG->noreplyaddress, get_string('noreplyname')); } } } if (!empty($replyto)) { $tempreplyto[] = array($replyto, $replytoname); } $mail->Subject = substr($subject, 0, 900); $temprecipients[] = array($user->email, fullname($user)); // Set word wrap. $mail->WordWrap = $wordwrapwidth; if (!empty($from->customheaders)) { // Add custom headers. if (is_array($from->customheaders)) { foreach ($from->customheaders as $customheader) { $mail->addCustomHeader($customheader); } } else { $mail->addCustomHeader($from->customheaders); } } if (!empty($from->priority)) { $mail->Priority = $from->priority; } if ($messagehtml && !empty($user->mailformat) && $user->mailformat == 1) { // Don't ever send HTML to users who don't want it. $mail->isHTML(true); $mail->Encoding = 'quoted-printable'; $mail->Body = $messagehtml; $mail->AltBody = "\n{$messagetext}\n"; } else { $mail->IsHTML(false); $mail->Body = "\n{$messagetext}\n"; } if ($attachment && $attachname) { if (preg_match("~\\.\\.~", $attachment)) { // Security check for ".." in dir path. $temprecipients[] = array($supportuser->email, fullname($supportuser, true)); $mail->addStringAttachment('Error in attachment. User attempted to attach a filename with a unsafe name.', 'error.txt', '8bit', 'text/plain'); } else { require_once $CFG->libdir . '/filelib.php'; $mimetype = mimeinfo('type', $attachname); $attachmentpath = $attachment; // Before doing the comparison, make sure that the paths are correct (Windows uses slashes in the other direction). $attachpath = str_replace('\\', '/', $attachmentpath); // Make sure both variables are normalised before comparing. $temppath = str_replace('\\', '/', $CFG->tempdir); // If the attachment is a full path to a file in the tempdir, use it as is, // otherwise assume it is a relative path from the dataroot (for backwards compatibility reasons). if (strpos($attachpath, realpath($temppath)) !== 0) { $attachmentpath = $CFG->dataroot . '/' . $attachmentpath; } $mail->addAttachment($attachmentpath, $attachname, 'base64', $mimetype); } } // Check if the email should be sent in an other charset then the default UTF-8. if (!empty($CFG->sitemailcharset) || !empty($CFG->allowusermailcharset)) { // Use the defined site mail charset or eventually the one preferred by the recipient. $charset = $CFG->sitemailcharset; if (!empty($CFG->allowusermailcharset)) { if ($useremailcharset = get_user_preferences('mailcharset', '0', $user->id)) { $charset = $useremailcharset; } } // Convert all the necessary strings if the charset is supported. $charsets = get_list_of_charsets(); unset($charsets['UTF-8']); if (in_array($charset, $charsets)) { $mail->CharSet = $charset; $mail->FromName = core_text::convert($mail->FromName, 'utf-8', strtolower($charset)); $mail->Subject = core_text::convert($mail->Subject, 'utf-8', strtolower($charset)); $mail->Body = core_text::convert($mail->Body, 'utf-8', strtolower($charset)); $mail->AltBody = core_text::convert($mail->AltBody, 'utf-8', strtolower($charset)); foreach ($temprecipients as $key => $values) { $temprecipients[$key][1] = core_text::convert($values[1], 'utf-8', strtolower($charset)); } foreach ($tempreplyto as $key => $values) { $tempreplyto[$key][1] = core_text::convert($values[1], 'utf-8', strtolower($charset)); } } } foreach ($temprecipients as $values) { $mail->addAddress($values[0], $values[1]); } foreach ($tempreplyto as $values) { $mail->addReplyTo($values[0], $values[1]); } if ($mail->send()) { set_send_count($user); if (!empty($mail->SMTPDebug)) { echo '</pre>'; } return true; } else { // Trigger event for failing to send email. $event = \core\event\email_failed::create(array('context' => context_system::instance(), 'userid' => $from->id, 'relateduserid' => $user->id, 'other' => array('subject' => $subject, 'message' => $messagetext, 'errorinfo' => $mail->ErrorInfo))); $event->trigger(); if (CLI_SCRIPT) { mtrace('Error: lib/moodlelib.php email_to_user(): ' . $mail->ErrorInfo); } if (!empty($mail->SMTPDebug)) { echo '</pre>'; } return false; } }
/** * Send an email to a specified user * * @param stdClass $user A {@link $USER} object * @param stdClass $from A {@link $USER} object * @param string $subject plain text subject line of the email * @param string $messagetext plain text version of the message * @param string $messagehtml complete html version of the message (optional) * @param string $attachment a file on the filesystem, either relative to $CFG->dataroot or a full path to a file in $CFG->tempdir * @param string $attachname the name of the file (extension indicates MIME) * @param bool $usetrueaddress determines whether $from email address should * be sent out. Will be overruled by user profile setting for maildisplay * @param string $replyto Email address to reply to * @param string $replytoname Name of reply to recipient * @param int $wordwrapwidth custom word wrap width, default 79 * @return bool Returns true if mail was sent OK and false if there was an error. */ function email_to_user($user, $from, $subject, $messagetext, $messagehtml = '', $attachment = '', $attachname = '', $usetrueaddress = true, $replyto = '', $replytoname = '', $wordwrapwidth = 79) { global $CFG, $PAGE, $SITE; if (empty($user) or empty($user->id)) { debugging('Can not send email to null user', DEBUG_DEVELOPER); return false; } if (empty($user->email)) { debugging('Can not send email to user without email: ' . $user->id, DEBUG_DEVELOPER); return false; } if (!empty($user->deleted)) { debugging('Can not send email to deleted user: '******'BEHAT_SITE_RUNNING')) { // Fake email sending in behat. return true; } if (!empty($CFG->noemailever)) { // Hidden setting for development sites, set in config.php if needed. debugging('Not sending email due to $CFG->noemailever config setting', DEBUG_NORMAL); return true; } if (email_should_be_diverted($user->email)) { $subject = "[DIVERTED {$user->email}] {$subject}"; $user = clone $user; $user->email = $CFG->divertallemailsto; } // Skip mail to suspended users. if (isset($user->auth) && $user->auth == 'nologin' or isset($user->suspended) && $user->suspended) { return true; } if (!validate_email($user->email)) { // We can not send emails to invalid addresses - it might create security issue or confuse the mailer. debugging("email_to_user: User {$user->id} (" . fullname($user) . ") email ({$user->email}) is invalid! Not sending."); return false; } if (over_bounce_threshold($user)) { debugging("email_to_user: User {$user->id} (" . fullname($user) . ") is over bounce threshold! Not sending."); return false; } // TLD .invalid is specifically reserved for invalid domain names. // For More information, see {@link http://tools.ietf.org/html/rfc2606#section-2}. if (substr($user->email, -8) == '.invalid') { debugging("email_to_user: User {$user->id} (" . fullname($user) . ") email domain ({$user->email}) is invalid! Not sending."); return true; // This is not an error. } // If the user is a remote mnet user, parse the email text for URL to the // wwwroot and modify the url to direct the user's browser to login at their // home site (identity provider - idp) before hitting the link itself. if (is_mnet_remote_user($user)) { require_once $CFG->dirroot . '/mnet/lib.php'; $jumpurl = mnet_get_idp_jump_url($user); $callback = partial('mnet_sso_apply_indirection', $jumpurl); $messagetext = preg_replace_callback("%({$CFG->wwwroot}[^[:space:]]*)%", $callback, $messagetext); $messagehtml = preg_replace_callback("%href=[\"'`]({$CFG->wwwroot}[\\w_:\\?=#&@/;.~-]*)[\"'`]%", $callback, $messagehtml); } $mail = get_mailer(); if (!empty($mail->SMTPDebug)) { echo '<pre>' . "\n"; } $temprecipients = array(); $tempreplyto = array(); // Make sure that we fall back onto some reasonable no-reply address. $noreplyaddress = empty($CFG->noreplyaddress) ? 'noreply@' . get_host_from_url($CFG->wwwroot) : $CFG->noreplyaddress; // 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 = $noreplyaddress; } $alloweddomains = null; if (!empty($CFG->allowedemaildomains)) { $alloweddomains = explode(PHP_EOL, $CFG->allowedemaildomains); } // Email will be sent using no reply address. if (empty($alloweddomains)) { $usetrueaddress = false; } if (is_string($from)) { // So we can pass whatever we want if there is need. $mail->From = $noreplyaddress; $mail->FromName = $from; // Check if using the true address is true, and the email is in the list of allowed domains for sending email, // and that the senders email setting is either displayed to everyone, or display to only other users that are enrolled // in a course with the sender. } else { if ($usetrueaddress && can_send_from_real_email_address($from, $user, $alloweddomains)) { $mail->From = $from->email; $fromdetails = new stdClass(); $fromdetails->name = fullname($from); $fromdetails->url = $CFG->wwwroot; $fromstring = $fromdetails->name; if ($CFG->emailfromvia == EMAIL_VIA_ALWAYS) { $fromstring = get_string('emailvia', 'core', $fromdetails); } $mail->FromName = $fromstring; if (empty($replyto)) { $tempreplyto[] = array($from->email, fullname($from)); } } else { $mail->From = $noreplyaddress; $fromdetails = new stdClass(); $fromdetails->name = fullname($from); $fromdetails->url = $CFG->wwwroot; $fromstring = $fromdetails->name; if ($CFG->emailfromvia != EMAIL_VIA_NEVER) { $fromstring = get_string('emailvia', 'core', $fromdetails); } $mail->FromName = $fromstring; if (empty($replyto)) { $tempreplyto[] = array($noreplyaddress, get_string('noreplyname')); } } } if (!empty($replyto)) { $tempreplyto[] = array($replyto, $replytoname); } $temprecipients[] = array($user->email, fullname($user)); // Set word wrap. $mail->WordWrap = $wordwrapwidth; if (!empty($from->customheaders)) { // Add custom headers. if (is_array($from->customheaders)) { foreach ($from->customheaders as $customheader) { $mail->addCustomHeader($customheader); } } else { $mail->addCustomHeader($from->customheaders); } } // If the X-PHP-Originating-Script email header is on then also add an additional // header with details of where exactly in moodle the email was triggered from, // either a call to message_send() or to email_to_user(). if (ini_get('mail.add_x_header')) { $stack = debug_backtrace(false); $origin = $stack[0]; foreach ($stack as $depth => $call) { if ($call['function'] == 'message_send') { $origin = $call; } } $originheader = $CFG->wwwroot . ' => ' . gethostname() . ':' . str_replace($CFG->dirroot . '/', '', $origin['file']) . ':' . $origin['line']; $mail->addCustomHeader('X-Moodle-Originating-Script: ' . $originheader); } if (!empty($from->priority)) { $mail->Priority = $from->priority; } $renderer = $PAGE->get_renderer('core'); $context = array('sitefullname' => $SITE->fullname, 'siteshortname' => $SITE->shortname, 'sitewwwroot' => $CFG->wwwroot, 'subject' => $subject, 'to' => $user->email, 'toname' => fullname($user), 'from' => $mail->From, 'fromname' => $mail->FromName); if (!empty($tempreplyto[0])) { $context['replyto'] = $tempreplyto[0][0]; $context['replytoname'] = $tempreplyto[0][1]; } if ($user->id > 0) { $context['touserid'] = $user->id; $context['tousername'] = $user->username; } if (!empty($user->mailformat) && $user->mailformat == 1) { // Only process html templates if the user preferences allow html email. if ($messagehtml) { // If html has been given then pass it through the template. $context['body'] = $messagehtml; $messagehtml = $renderer->render_from_template('core/email_html', $context); } else { // If no html has been given, BUT there is an html wrapping template then // auto convert the text to html and then wrap it. $autohtml = trim(text_to_html($messagetext)); $context['body'] = $autohtml; $temphtml = $renderer->render_from_template('core/email_html', $context); if ($autohtml != $temphtml) { $messagehtml = $temphtml; } } } $context['body'] = $messagetext; $mail->Subject = $renderer->render_from_template('core/email_subject', $context); $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); $mail->Encoding = 'quoted-printable'; $mail->Body = $messagehtml; $mail->AltBody = "\n{$messagetext}\n"; } else { $mail->IsHTML(false); $mail->Body = "\n{$messagetext}\n"; } if ($attachment && $attachname) { if (preg_match("~\\.\\.~", $attachment)) { // Security check for ".." in dir path. $temprecipients[] = array($supportuser->email, fullname($supportuser, true)); $mail->addStringAttachment('Error in attachment. User attempted to attach a filename with a unsafe name.', 'error.txt', '8bit', 'text/plain'); } else { require_once $CFG->libdir . '/filelib.php'; $mimetype = mimeinfo('type', $attachname); $attachmentpath = $attachment; // Before doing the comparison, make sure that the paths are correct (Windows uses slashes in the other direction). $attachpath = str_replace('\\', '/', $attachmentpath); // Make sure both variables are normalised before comparing. $temppath = str_replace('\\', '/', realpath($CFG->tempdir)); // If the attachment is a full path to a file in the tempdir, use it as is, // otherwise assume it is a relative path from the dataroot (for backwards compatibility reasons). if (strpos($attachpath, $temppath) !== 0) { $attachmentpath = $CFG->dataroot . '/' . $attachmentpath; } $mail->addAttachment($attachmentpath, $attachname, 'base64', $mimetype); } } // Check if the email should be sent in an other charset then the default UTF-8. if (!empty($CFG->sitemailcharset) || !empty($CFG->allowusermailcharset)) { // Use the defined site mail charset or eventually the one preferred by the recipient. $charset = $CFG->sitemailcharset; if (!empty($CFG->allowusermailcharset)) { if ($useremailcharset = get_user_preferences('mailcharset', '0', $user->id)) { $charset = $useremailcharset; } } // Convert all the necessary strings if the charset is supported. $charsets = get_list_of_charsets(); unset($charsets['UTF-8']); if (in_array($charset, $charsets)) { $mail->CharSet = $charset; $mail->FromName = core_text::convert($mail->FromName, 'utf-8', strtolower($charset)); $mail->Subject = core_text::convert($mail->Subject, 'utf-8', strtolower($charset)); $mail->Body = core_text::convert($mail->Body, 'utf-8', strtolower($charset)); $mail->AltBody = core_text::convert($mail->AltBody, 'utf-8', strtolower($charset)); foreach ($temprecipients as $key => $values) { $temprecipients[$key][1] = core_text::convert($values[1], 'utf-8', strtolower($charset)); } foreach ($tempreplyto as $key => $values) { $tempreplyto[$key][1] = core_text::convert($values[1], 'utf-8', strtolower($charset)); } } } foreach ($temprecipients as $values) { $mail->addAddress($values[0], $values[1]); } foreach ($tempreplyto as $values) { $mail->addReplyTo($values[0], $values[1]); } if ($mail->send()) { set_send_count($user); if (!empty($mail->SMTPDebug)) { echo '</pre>'; } return true; } else { // Trigger event for failing to send email. $event = \core\event\email_failed::create(array('context' => context_system::instance(), 'userid' => $from->id, 'relateduserid' => $user->id, 'other' => array('subject' => $subject, 'message' => $messagetext, 'errorinfo' => $mail->ErrorInfo))); $event->trigger(); if (CLI_SCRIPT) { mtrace('Error: lib/moodlelib.php email_to_user(): ' . $mail->ErrorInfo); } if (!empty($mail->SMTPDebug)) { echo '</pre>'; } return false; } }
/** * Always use this function for all emails to users * * @param object $userto user object to send email to. must contain firstname,lastname,preferredname,email * @param object $userfrom user object to send email from. If null, email will come from mahara * @param string $subject email subject * @param string $messagetext text version of email * @param string $messagehtml html version of email (will send both html and text) * @param array $customheaders email headers * @throws EmailException * @throws EmailDisabledException */ function email_user($userto, $userfrom, $subject, $messagetext, $messagehtml = '', $customheaders = null) { global $IDPJUMPURL; static $mnetjumps = array(); if (!get_config('sendemail')) { // You can entirely disable Mahara from sending any e-mail via the // 'sendemail' configuration variable return true; } if (empty($userto)) { throw new InvalidArgumentException("empty user given to email_user"); } if (!($mailinfo = can_receive_email($userto))) { throw new EmailDisabledException("email for this user has been disabled"); } // If the user is a remote xmlrpc user, trawl through the email text for URLs // to our wwwroot and modify the url to direct the user's browser to login at // their home site before hitting the link on this site if (!empty($userto->mnethostwwwroot) && !empty($userto->mnethostapp)) { require_once get_config('docroot') . 'auth/xmlrpc/lib.php'; // Form the request url to hit the idp's jump.php if (isset($mnetjumps[$userto->mnethostwwwroot])) { $IDPJUMPURL = $mnetjumps[$userto->mnethostwwwroot]; } else { $mnetjumps[$userto->mnethostwwwroot] = $IDPJUMPURL = PluginAuthXmlrpc::get_jump_url_prefix($userto->mnethostwwwroot, $userto->mnethostapp); } $wwwroot = get_config('wwwroot'); $messagetext = preg_replace_callback('%(' . $wwwroot . '([\\w_:\\?=#&@/;.~-]*))%', 'localurl_to_jumpurl', $messagetext); $messagehtml = preg_replace_callback('%href=["\'`](' . $wwwroot . '([\\w_:\\?=#&@/;.~-]*))["\'`]%', 'localurl_to_jumpurl', $messagehtml); } require_once 'phpmailer/class.phpmailer.php'; $mail = new phpmailer(); // Leaving this commented out - there's no reason for people to know this //$mail->Version = 'Mahara ' . get_config('release'); $mail->PluginDir = get_config('libroot') . 'phpmailer/'; $mail->CharSet = 'UTF-8'; $smtphosts = get_config('smtphosts'); if ($smtphosts == 'qmail') { // use Qmail system $mail->IsQmail(); } else { if (empty($smtphosts)) { // use PHP mail() = sendmail $mail->IsMail(); } else { $mail->IsSMTP(); // use SMTP directly $mail->Host = get_config('smtphosts'); if (get_config('smtpuser')) { // Use SMTP authentication $mail->SMTPAuth = true; $mail->Username = get_config('smtpuser'); $mail->Password = get_config('smtppass'); } } } if (get_config('bounces_handle') && isset($mailinfo->owner)) { $mail->Sender = generate_email_processing_address($mailinfo->owner, $userto); } if (empty($userfrom) || $userfrom->email == get_config('noreplyaddress')) { if (empty($mail->Sender)) { $mail->Sender = get_config('noreplyaddress'); } $mail->From = get_config('noreplyaddress'); $mail->FromName = isset($userfrom->id) ? display_name($userfrom, $userto) : get_config('sitename'); $customheaders[] = 'Precedence: Bulk'; // Try to avoid pesky out of office responses $messagetext .= "\n\n" . get_string('pleasedonotreplytothismessage') . "\n"; if ($messagehtml) { $messagehtml .= "\n\n<p>" . get_string('pleasedonotreplytothismessage') . "</p>\n"; } } else { if (empty($mail->Sender)) { $mail->Sender = $userfrom->email; } $mail->From = $userfrom->email; $mail->FromName = display_name($userfrom, $userto); } $replytoset = false; if (!empty($customheaders) && is_array($customheaders)) { foreach ($customheaders as $customheader) { $mail->AddCustomHeader($customheader); if (0 === stripos($customheader, 'reply-to')) { $replytoset = true; } } } if (!$replytoset) { $mail->AddReplyTo($mail->From, $mail->FromName); } $mail->Subject = substr(stripslashes($subject), 0, 900); if ($to = get_config('sendallemailto')) { // Admins can configure the system to send all email to a given address // instead of whoever would receive it, useful for debugging. $mail->addAddress($to); $notice = get_string('debugemail', 'mahara', display_name($userto, $userto), $userto->email); $messagetext = $notice . "\n\n" . $messagetext; if ($messagehtml) { $messagehtml = '<p>' . hsc($notice) . '</p>' . $messagehtml; } $usertoname = display_name($userto, $userto, true) . ' (' . get_string('divertingemailto', 'mahara', $to) . ')'; } else { $usertoname = display_name($userto, $userto); if (empty($userto->email)) { throw new EmailException("Cannot send email to {$usertoname} with subject {$subject}. User has no primary email address set."); } $mail->AddAddress($userto->email, $usertoname); $to = $userto->email; } $mail->WordWrap = 79; if ($messagehtml) { $mail->IsHTML(true); $mail->Encoding = 'quoted-printable'; $mail->Body = $messagehtml; $mail->AltBody = $messagetext; } else { $mail->IsHTML(false); $mail->Body = $messagetext; } if ($mail->Send()) { if ($logfile = get_config('emaillog')) { $docroot = get_config('docroot'); @($client = (string) $_SERVER['REMOTE_ADDR']); @($script = (string) $_SERVER['SCRIPT_FILENAME']); if (strpos($script, $docroot) === 0) { $script = substr($script, strlen($docroot)); } $line = "{$to} <- {$mail->From} - " . str_shorten_text($mail->Subject, 200); @error_log('[' . date("Y-m-d h:i:s") . "] [{$client}] [{$script}] {$line}\n", 3, $logfile); } // Update the count of sent mail update_send_count($userto); return true; } throw new EmailException("Couldn't send email to {$usertoname} with subject {$subject}. " . "Error from phpmailer was: " . $mail->ErrorInfo); }
/** * Send an email to a specified user * * @uses $CFG * @uses $FULLME * @uses $MNETIDPJUMPURL IdentityProvider(IDP) URL user hits to jump to mnet peer. * @uses SITEID * @param user $user A {@link $USER} object * @param user $from A {@link $USER} object * @param string $subject plain text subject line of the email * @param string $messagetext plain text version of the message * @param string $messagehtml complete html version of the message (optional) * @param string $attachment a file on the filesystem, relative to $CFG->dataroot * @param string $attachname the name of the file (extension indicates MIME) * @param bool $usetrueaddress determines whether $from email address should * be sent out. Will be overruled by user profile setting for maildisplay * @param int $wordwrapwidth custom word wrap width * @return bool|string Returns "true" if mail was sent OK, "emailstop" if email * was blocked by user and "false" if there was another sort of error. */ function email_to_user($user, $from, $subject, $messagetext, $messagehtml = '', $attachment = '', $attachname = '', $usetrueaddress = true, $replyto = '', $replytoname = '', $wordwrapwidth = 79) { global $CFG, $FULLME, $MNETIDPJUMPURL; static $mnetjumps = array(); if (empty($user) || empty($user->email)) { return false; } if (!empty($user->deleted)) { // do not mail delted users return false; } if (!empty($CFG->noemailever)) { // hidden setting for development sites, set in config.php if needed return true; } // skip mail to suspended users if (isset($user->auth) && $user->auth == 'nologin') { return true; } if (!empty($user->emailstop)) { return 'emailstop'; } if (over_bounce_threshold($user)) { error_log("User {$user->id} (" . fullname($user) . ") is over bounce threshold! Not sending."); return false; } // If the user is a remote mnet user, parse the email text for URL to the // wwwroot and modify the url to direct the user's browser to login at their // home site (identity provider - idp) before hitting the link itself if (is_mnet_remote_user($user)) { require_once $CFG->dirroot . '/mnet/lib.php'; // Form the request url to hit the idp's jump.php if (isset($mnetjumps[$user->mnethostid])) { $MNETIDPJUMPURL = $mnetjumps[$user->mnethostid]; } else { $idp = mnet_get_peer_host($user->mnethostid); $idpjumppath = '/auth/mnet/jump.php'; $MNETIDPJUMPURL = $idp->wwwroot . $idpjumppath . '?hostwwwroot=' . $CFG->wwwroot . '&wantsurl='; $mnetjumps[$user->mnethostid] = $MNETIDPJUMPURL; } $messagetext = preg_replace_callback("%({$CFG->wwwroot}[^[:space:]]*)%", 'mnet_sso_apply_indirection', $messagetext); $messagehtml = preg_replace_callback("%href=[\"'`]({$CFG->wwwroot}[\\w_:\\?=#&@/;.~-]*)[\"'`]%", 'mnet_sso_apply_indirection', $messagehtml); } $mail =& get_mailer(); if (!empty($mail->SMTPDebug)) { echo '<pre>' . "\n"; } /// 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; } if (is_string($from)) { // So we can pass whatever we want if there is need $mail->From = $CFG->noreplyaddress; $mail->FromName = $from; } else { if ($usetrueaddress and $from->maildisplay) { $mail->From = stripslashes($from->email); $mail->FromName = fullname($from); } else { $mail->From = $CFG->noreplyaddress; $mail->FromName = fullname($from); if (empty($replyto)) { $mail->AddReplyTo($CFG->noreplyaddress, get_string('noreplyname')); } } } if (!empty($replyto)) { $mail->AddReplyTo($replyto, $replytoname); } $mail->Subject = substr(stripslashes($subject), 0, 900); $mail->AddAddress(stripslashes($user->email), fullname($user)); $mail->WordWrap = $wordwrapwidth; // set word wrap if (!empty($from->customheaders)) { // Add custom headers if (is_array($from->customheaders)) { foreach ($from->customheaders as $customheader) { $mail->AddCustomHeader($customheader); } } else { $mail->AddCustomHeader($from->customheaders); } } if (!empty($from->priority)) { $mail->Priority = $from->priority; } if ($messagehtml && $user->mailformat == 1) { // Don't ever send HTML to users who don't want it $mail->IsHTML(true); $mail->Encoding = 'quoted-printable'; // Encoding to use $mail->Body = $messagehtml; $mail->AltBody = "\n{$messagetext}\n"; } else { $mail->IsHTML(false); $mail->Body = "\n{$messagetext}\n"; } if ($attachment && $attachname) { if (ereg("\\.\\.", $attachment)) { // Security check for ".." in dir path $mail->AddAddress($supportuser->email, fullname($supportuser, true)); $mail->AddStringAttachment('Error in attachment. User attempted to attach a filename with a unsafe name.', 'error.txt', '8bit', 'text/plain'); } else { require_once $CFG->libdir . '/filelib.php'; $mimetype = mimeinfo('type', $attachname); $mail->AddAttachment($CFG->dataroot . '/' . $attachment, $attachname, 'base64', $mimetype); } } /// If we are running under Unicode and sitemailcharset or allowusermailcharset are set, convert the email /// encoding to the specified one if (!empty($CFG->sitemailcharset) || !empty($CFG->allowusermailcharset)) { /// Set it to site mail charset $charset = $CFG->sitemailcharset; /// Overwrite it with the user mail charset if (!empty($CFG->allowusermailcharset)) { if ($useremailcharset = get_user_preferences('mailcharset', '0', $user->id)) { $charset = $useremailcharset; } } /// If it has changed, convert all the necessary strings $charsets = get_list_of_charsets(); unset($charsets['UTF-8']); if (in_array($charset, $charsets)) { /// Save the new mail charset $mail->CharSet = $charset; /// And convert some strings $mail->FromName = $textlib->convert($mail->FromName, 'utf-8', $mail->CharSet); //From Name foreach ($mail->ReplyTo as $key => $rt) { //ReplyTo Names $mail->ReplyTo[$key][1] = $textlib->convert($rt[1], 'utf-8', $mail->CharSet); } $mail->Subject = $textlib->convert($mail->Subject, 'utf-8', $mail->CharSet); //Subject foreach ($mail->to as $key => $to) { $mail->to[$key][1] = $textlib->convert($to[1], 'utf-8', $mail->CharSet); //To Names } $mail->Body = $textlib->convert($mail->Body, 'utf-8', $mail->CharSet); //Body $mail->AltBody = $textlib->convert($mail->AltBody, 'utf-8', $mail->CharSet); //Subject } } if ($mail->Send()) { set_send_count($user); $mail->IsSMTP(); // use SMTP directly if (!empty($mail->SMTPDebug)) { echo '</pre>'; } return true; } else { mtrace('ERROR: ' . $mail->ErrorInfo); add_to_log(SITEID, 'library', 'mailer', $FULLME, 'ERROR: ' . $mail->ErrorInfo); if (!empty($mail->SMTPDebug)) { echo '</pre>'; } return false; } }
/** * Send an email to a specified user * * @global object * @global string * @global string IdentityProvider(IDP) URL user hits to jump to mnet peer. * @uses SITEID * @param stdClass $user A {@link $USER} object * @param stdClass $from A {@link $USER} object * @param string $subject plain text subject line of the email * @param string $messagetext plain text version of the message * @param string $messagehtml complete html version of the message (optional) * @param string $attachment a file on the filesystem, relative to $CFG->dataroot * @param string $attachname the name of the file (extension indicates MIME) * @param bool $usetrueaddress determines whether $from email address should * be sent out. Will be overruled by user profile setting for maildisplay * @param string $replyto Email address to reply to * @param string $replytoname Name of reply to recipient * @param int $wordwrapwidth custom word wrap width, default 79 * @return bool Returns true if mail was sent OK and false if there was an error. */ function email_to_user($user, $from, $subject, $messagetext, $messagehtml = '', $attachment = '', $attachname = '', $usetrueaddress = true, $replyto = '', $replytoname = '', $wordwrapwidth = 79) { global $CFG, $FULLME; if (empty($user) || empty($user->email)) { mtrace('Error: lib/moodlelib.php email_to_user(): User is null or has no email'); return false; } if (!empty($user->deleted)) { // do not mail delted users mtrace('Error: lib/moodlelib.php email_to_user(): User is deleted'); return false; } if (!empty($CFG->noemailever)) { // hidden setting for development sites, set in config.php if needed mtrace('Error: lib/moodlelib.php email_to_user(): Not sending email due to noemailever config setting'); return true; } if (!empty($CFG->divertallemailsto)) { $subject = "[DIVERTED {$user->email}] {$subject}"; $user = clone $user; $user->email = $CFG->divertallemailsto; } // skip mail to suspended users if (isset($user->auth) && $user->auth == 'nologin') { return true; } if (over_bounce_threshold($user)) { $bouncemsg = "User {$user->id} (" . fullname($user) . ") is over bounce threshold! Not sending."; error_log($bouncemsg); mtrace('Error: lib/moodlelib.php email_to_user(): ' . $bouncemsg); return false; } // If the user is a remote mnet user, parse the email text for URL to the // wwwroot and modify the url to direct the user's browser to login at their // home site (identity provider - idp) before hitting the link itself if (is_mnet_remote_user($user)) { require_once $CFG->dirroot . '/mnet/lib.php'; $jumpurl = mnet_get_idp_jump_url($user); $callback = partial('mnet_sso_apply_indirection', $jumpurl); $messagetext = preg_replace_callback("%({$CFG->wwwroot}[^[:space:]]*)%", $callback, $messagetext); $messagehtml = preg_replace_callback("%href=[\"'`]({$CFG->wwwroot}[\\w_:\\?=#&@/;.~-]*)[\"'`]%", $callback, $messagehtml); } $mail = get_mailer(); if (!empty($mail->SMTPDebug)) { echo '<pre>' . "\n"; } $temprecipients = array(); $tempreplyto = array(); $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; } if (is_string($from)) { // So we can pass whatever we want if there is need $mail->From = $CFG->noreplyaddress; $mail->FromName = $from; } else { if ($usetrueaddress and $from->maildisplay) { $mail->From = $from->email; $mail->FromName = fullname($from); } else { $mail->From = $CFG->noreplyaddress; $mail->FromName = fullname($from); if (empty($replyto)) { $tempreplyto[] = array($CFG->noreplyaddress, get_string('noreplyname')); } } } if (!empty($replyto)) { $tempreplyto[] = array($replyto, $replytoname); } $mail->Subject = substr($subject, 0, 900); $temprecipients[] = array($user->email, fullname($user)); $mail->WordWrap = $wordwrapwidth; // set word wrap if (!empty($from->customheaders)) { // Add custom headers if (is_array($from->customheaders)) { foreach ($from->customheaders as $customheader) { $mail->AddCustomHeader($customheader); } } else { $mail->AddCustomHeader($from->customheaders); } } if (!empty($from->priority)) { $mail->Priority = $from->priority; } if ($messagehtml && !empty($user->mailformat) && $user->mailformat == 1) { // Don't ever send HTML to users who don't want it $mail->IsHTML(true); $mail->Encoding = 'quoted-printable'; // Encoding to use $mail->Body = $messagehtml; $mail->AltBody = "\n{$messagetext}\n"; } else { $mail->IsHTML(false); $mail->Body = "\n{$messagetext}\n"; } if ($attachment && $attachname) { if (preg_match("~\\.\\.~", $attachment)) { // Security check for ".." in dir path $temprecipients[] = array($supportuser->email, fullname($supportuser, true)); $mail->AddStringAttachment('Error in attachment. User attempted to attach a filename with a unsafe name.', 'error.txt', '8bit', 'text/plain'); } else { require_once $CFG->libdir . '/filelib.php'; $mimetype = mimeinfo('type', $attachname); $mail->AddAttachment($CFG->dataroot . '/' . $attachment, $attachname, 'base64', $mimetype); } } // Check if the email should be sent in an other charset then the default UTF-8 if (!empty($CFG->sitemailcharset) || !empty($CFG->allowusermailcharset)) { // use the defined site mail charset or eventually the one preferred by the recipient $charset = $CFG->sitemailcharset; if (!empty($CFG->allowusermailcharset)) { if ($useremailcharset = get_user_preferences('mailcharset', '0', $user->id)) { $charset = $useremailcharset; } } // convert all the necessary strings if the charset is supported $charsets = get_list_of_charsets(); unset($charsets['UTF-8']); if (in_array($charset, $charsets)) { $textlib = textlib_get_instance(); $mail->CharSet = $charset; $mail->FromName = $textlib->convert($mail->FromName, 'utf-8', strtolower($charset)); $mail->Subject = $textlib->convert($mail->Subject, 'utf-8', strtolower($charset)); $mail->Body = $textlib->convert($mail->Body, 'utf-8', strtolower($charset)); $mail->AltBody = $textlib->convert($mail->AltBody, 'utf-8', strtolower($charset)); foreach ($temprecipients as $key => $values) { $temprecipients[$key][1] = $textlib->convert($values[1], 'utf-8', strtolower($charset)); } foreach ($tempreplyto as $key => $values) { $tempreplyto[$key][1] = $textlib->convert($values[1], 'utf-8', strtolower($charset)); } } } foreach ($temprecipients as $values) { $mail->AddAddress($values[0], $values[1]); } foreach ($tempreplyto as $values) { $mail->AddReplyTo($values[0], $values[1]); } if ($mail->Send()) { set_send_count($user); $mail->IsSMTP(); // use SMTP directly if (!empty($mail->SMTPDebug)) { echo '</pre>'; } return true; } else { mtrace('ERROR: ' . $mail->ErrorInfo); add_to_log(SITEID, 'library', 'mailer', $FULLME, 'ERROR: ' . $mail->ErrorInfo); if (!empty($mail->SMTPDebug)) { echo '</pre>'; } return false; } }
/** * Always use this function for all emails to users * * @param object $userto user object to send email to. must contain firstname,lastname,preferredname,email * @param object $userfrom user object to send email from. If null, email will come from mahara * @param string $subject email subject * @param string $messagetext text version of email * @param string $messagehtml html version of email (will send both html and text) * @param array $customheaders email headers * @throws EmailException * @throws EmailDisabledException */ function email_user($userto, $userfrom, $subject, $messagetext, $messagehtml = '', $customheaders = null) { global $IDPJUMPURL; static $mnetjumps = array(); if (!get_config('sendemail')) { // You can entirely disable Mahara from sending any e-mail via the // 'sendemail' configuration variable return true; } if (empty($userto)) { throw new InvalidArgumentException("empty user given to email_user"); } if (isset($userto->id) && empty($userto->ignoredisabled)) { $maildisabled = property_exists($userto, 'maildisabled') ? $userto->maildisabled : get_account_preference($userto->id, 'maildisabled') == 1; if ($maildisabled) { throw new EmailDisabledException("email for this user has been disabled"); } } // If the user is a remote xmlrpc user, trawl through the email text for URLs // to our wwwroot and modify the url to direct the user's browser to login at // their home site before hitting the link on this site if (!empty($userto->mnethostwwwroot) && !empty($userto->mnethostapp)) { require_once get_config('docroot') . 'auth/xmlrpc/lib.php'; // Form the request url to hit the idp's jump.php if (isset($mnetjumps[$userto->mnethostwwwroot])) { $IDPJUMPURL = $mnetjumps[$userto->mnethostwwwroot]; } else { $mnetjumps[$userto->mnethostwwwroot] = $IDPJUMPURL = PluginAuthXmlrpc::get_jump_url_prefix($userto->mnethostwwwroot, $userto->mnethostapp); } $wwwroot = get_config('wwwroot'); $messagetext = preg_replace_callback('%(' . $wwwroot . '([\\w_:\\?=#&@/;.~-]*))%', 'localurl_to_jumpurl', $messagetext); $messagehtml = preg_replace_callback('%href=["\'`](' . $wwwroot . '([\\w_:\\?=#&@/;.~-]*))["\'`]%', 'localurl_to_jumpurl', $messagehtml); } require_once 'phpmailer/PHPMailerAutoload.php'; $mail = new PHPMailer(true); $mail->CharSet = 'UTF-8'; $smtphosts = get_config('smtphosts'); if ($smtphosts == 'qmail') { // use Qmail system $mail->IsQmail(); } else { if (empty($smtphosts)) { // use PHP mail() = sendmail $mail->IsMail(); } else { $mail->IsSMTP(); // use SMTP directly $mail->Host = get_config('smtphosts'); if (get_config('smtpuser')) { // Use SMTP authentication $mail->SMTPAuth = true; $mail->Username = get_config('smtpuser'); $mail->Password = get_config('smtppass'); $mail->SMTPSecure = get_config('smtpsecure'); $mail->Port = get_config('smtpport'); if (get_config('smtpsecure') && !get_config('smtpport')) { // Encrypted connection with no port. Use default one. if (get_config('smtpsecure') == 'ssl') { $mail->Port = 465; } elseif (get_config('smtpsecure') == 'tls') { $mail->Port = 587; } } } } } if (get_config('bounces_handle') && !empty($userto->id) && empty($maildisabled)) { $mail->Sender = generate_email_processing_address($userto->id, $userto); } if (empty($userfrom) || $userfrom->email == get_config('noreplyaddress')) { if (empty($mail->Sender)) { $mail->Sender = get_config('noreplyaddress'); } $mail->From = get_config('noreplyaddress'); $mail->FromName = isset($userfrom->id) ? display_name($userfrom, $userto) : get_config('sitename'); $customheaders[] = 'Precedence: Bulk'; // Try to avoid pesky out of office responses $messagetext .= "\n\n" . get_string('pleasedonotreplytothismessage') . "\n"; if ($messagehtml) { $messagehtml .= "\n\n<p>" . get_string('pleasedonotreplytothismessage') . "</p>\n"; } } else { if (empty($mail->Sender)) { $mail->Sender = $userfrom->email; } $mail->From = $userfrom->email; $mail->FromName = display_name($userfrom, $userto); } $replytoset = false; if (!empty($customheaders) && is_array($customheaders)) { foreach ($customheaders as $customheader) { // To prevent duplicated declaration of the field "Message-ID", // don't add it into the $mail->CustomHeader[]. if (false === stripos($customheader, 'message-id')) { // Hack the fields "In-Reply-To" and "References": // add touser<userID> if (0 === stripos($customheader, 'in-reply-to') || 0 === stripos($customheader, 'references')) { $customheader = preg_replace('/<forumpost(\\d+)/', '<forumpost${1}touser' . $userto->id, $customheader); } $mail->AddCustomHeader($customheader); } else { list($h, $msgid) = explode(':', $customheader, 2); // Hack the "Message-ID": add touser<userID> to make sure // the "Message-ID" is unique $msgid = preg_replace('/<forumpost(\\d+)/', '<forumpost${1}touser' . $userto->id, $msgid); $mail->MessageID = trim($msgid); } if (0 === stripos($customheader, 'reply-to')) { $replytoset = true; } } } $mail->Subject = substr(stripslashes($subject), 0, 900); try { if ($to = get_config('sendallemailto')) { // Admins can configure the system to send all email to a given address // instead of whoever would receive it, useful for debugging. $usertoname = display_name($userto, $userto, true) . ' (' . get_string('divertingemailto', 'mahara', $to) . ')'; $mail->addAddress($to); $notice = get_string('debugemail', 'mahara', display_name($userto, $userto), $userto->email); $messagetext = $notice . "\n\n" . $messagetext; if ($messagehtml) { $messagehtml = '<p>' . hsc($notice) . '</p>' . $messagehtml; } } else { $usertoname = display_name($userto, $userto); $mail->AddAddress($userto->email, $usertoname); $to = $userto->email; } if (!$replytoset) { $mail->AddReplyTo($mail->From, $mail->FromName); } } catch (phpmailerException $e) { // If there's a phpmailer error already, assume it's an invalid address throw new InvalidEmailException("Cannot send email to {$usertoname} with subject {$subject}. Error from phpmailer was: " . $mail->ErrorInfo); } $mail->WordWrap = 79; if ($messagehtml) { $mail->IsHTML(true); $mail->Encoding = 'quoted-printable'; $mail->Body = $messagehtml; $mail->AltBody = $messagetext; } else { $mail->IsHTML(false); $mail->Body = $messagetext; } try { $sent = $mail->Send(); } catch (phpmailerException $e) { $sent = false; } if ($sent) { if ($logfile = get_config('emaillog')) { $docroot = get_config('docroot'); @($client = (string) $_SERVER['REMOTE_ADDR']); @($script = (string) $_SERVER['SCRIPT_FILENAME']); if (strpos($script, $docroot) === 0) { $script = substr($script, strlen($docroot)); } $line = "{$to} <- {$mail->From} - " . str_shorten_text($mail->Subject, 200); @error_log('[' . date("Y-m-d h:i:s") . "] [{$client}] [{$script}] {$line}\n", 3, $logfile); } if (get_config('bounces_handle')) { // Update the count of sent mail update_send_count($userto); } return true; } throw new EmailException("Couldn't send email to {$usertoname} with subject {$subject}. " . "Error from phpmailer was: " . $mail->ErrorInfo); }
/** * Send an email to a specified user * * @uses $CFG * @uses $FULLME * @uses SITEID * @param user $user A {@link $USER} object * @param user $from A {@link $USER} object * @param string $subject plain text subject line of the email * @param string $messagetext plain text version of the message * @param string $messagehtml complete html version of the message (optional) * @param string $attachment a file on the filesystem, relative to $CFG->dataroot * @param string $attachname the name of the file (extension indicates MIME) * @param bool $usetrueaddress determines whether $from email address should * be sent out. Will be overruled by user profile setting for maildisplay * @return bool|string Returns "true" if mail was sent OK, "emailstop" if email * was blocked by user and "false" if there was another sort of error. */ function email_to_user($user, $from, $subject, $messagetext, $messagehtml = '', $attachment = '', $attachname = '', $usetrueaddress = true, $replyto = '', $replytoname = '') { 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; } // skip mail to suspended users if (isset($user->auth) && $user->auth == 'nologin') { return true; } if (!empty($user->emailstop)) { return 'emailstop'; } if (over_bounce_threshold($user)) { error_log("User {$user->id} (" . fullname($user) . ") is over bounce threshold! Not sending."); return false; } $mail = new phpmailer(); $mail->Version = 'Moodle ' . $CFG->version; // mailer version $mail->PluginDir = $CFG->libdir . '/phpmailer/'; // plugin directory (eg smtp plugin) $mail->CharSet = 'UTF-8'; 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 '<pre>' . "\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; } } } $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; } if (is_string($from)) { // So we can pass whatever we want if there is need $mail->From = $CFG->noreplyaddress; $mail->FromName = $from; } else { if ($usetrueaddress and $from->maildisplay) { $mail->From = $from->email; $mail->FromName = fullname($from); } else { $mail->From = $CFG->noreplyaddress; $mail->FromName = fullname($from); if (empty($replyto)) { $mail->AddReplyTo($CFG->noreplyaddress, get_string('noreplyname')); } } } if (!empty($replyto)) { $mail->AddReplyTo($replyto, $replytoname); } $mail->Subject = substr(stripslashes($subject), 0, 900); $mail->AddAddress($user->email, fullname($user)); $mail->WordWrap = 79; // set word wrap if (!empty($from->customheaders)) { // Add custom headers if (is_array($from->customheaders)) { foreach ($from->customheaders as $customheader) { $mail->AddCustomHeader($customheader); } } else { $mail->AddCustomHeader($from->customheaders); } } if (!empty($from->priority)) { $mail->Priority = $from->priority; } if ($messagehtml && $user->mailformat == 1) { // Don't ever send HTML to users who don't want it $mail->IsHTML(true); $mail->Encoding = 'quoted-printable'; // Encoding to use $mail->Body = $messagehtml; $mail->AltBody = "\n{$messagetext}\n"; } else { $mail->IsHTML(false); $mail->Body = "\n{$messagetext}\n"; } if ($attachment && $attachname) { if (ereg("\\.\\.", $attachment)) { // Security check for ".." in dir path $mail->AddAddress($supportuser->email, fullname($supportuser, true)); $mail->AddStringAttachment('Error in attachment. User attempted to attach a filename with a unsafe name.', 'error.txt', '8bit', 'text/plain'); } else { require_once $CFG->libdir . '/filelib.php'; $mimetype = mimeinfo('type', $attachname); $mail->AddAttachment($CFG->dataroot . '/' . $attachment, $attachname, 'base64', $mimetype); } } /// If we are running under Unicode and sitemailcharset or allowusermailcharset are set, convert the email /// encoding to the specified one if (!empty($CFG->sitemailcharset) || !empty($CFG->allowusermailcharset)) { /// Set it to site mail charset $charset = $CFG->sitemailcharset; /// Overwrite it with the user mail charset if (!empty($CFG->allowusermailcharset)) { if ($useremailcharset = get_user_preferences('mailcharset', '0', $user->id)) { $charset = $useremailcharset; } } /// If it has changed, convert all the necessary strings $charsets = get_list_of_charsets(); unset($charsets['UTF-8']); if (in_array($charset, $charsets)) { /// Save the new mail charset $mail->CharSet = $charset; /// And convert some strings $mail->FromName = $textlib->convert($mail->FromName, 'utf-8', $mail->CharSet); //From Name foreach ($mail->ReplyTo as $key => $rt) { //ReplyTo Names $mail->ReplyTo[$key][1] = $textlib->convert($rt, 'utf-8', $mail->CharSet); } $mail->Subject = $textlib->convert($mail->Subject, 'utf-8', $mail->CharSet); //Subject foreach ($mail->to as $key => $to) { $mail->to[$key][1] = $textlib->convert($to, 'utf-8', $mail->CharSet); //To Names } $mail->Body = $textlib->convert($mail->Body, 'utf-8', $mail->CharSet); //Body $mail->AltBody = $textlib->convert($mail->AltBody, 'utf-8', $mail->CharSet); //Subject } } if ($mail->Send()) { set_send_count($user); $mail->IsSMTP(); // use SMTP directly if (!empty($CFG->debugsmtp)) { echo '</pre>'; } return true; } else { mtrace('ERROR: ' . $mail->ErrorInfo); add_to_log(SITEID, 'library', 'mailer', $FULLME, 'ERROR: ' . $mail->ErrorInfo); if (!empty($CFG->debugsmtp)) { echo '</pre>'; } return false; } }