43 protected static function sendWithPear( $mailer, $dest, $headers, $body ) {
44 $mailResult = $mailer->send( $dest, $headers, $body );
47 if ( PEAR::isError( $mailResult ) ) {
48 wfDebug(
"PEAR::Mail failed: " . $mailResult->getMessage() .
"\n" );
69 foreach ( $headers as $name => $value ) {
72 $strings[] =
"$name: $value";
74 return implode( $endl, $strings );
86 $msgid = uniqid( $domainId .
".",
true );
91 $domain = $url[
'host'];
93 return "<$msgid@$domain>";
115 public static function send( $to, $from, $subject, $body, $options = [] ) {
118 if ( !isset( $options[
'contentType'] ) ) {
119 $options[
'contentType'] =
'text/plain; charset=UTF-8';
122 if ( !is_array( $to ) ) {
133 !is_array( $body ) &&
134 strlen( $body ) >= $minBodyLen
139 isset( $body[
'text'] ) &&
140 isset( $body[
'html'] ) &&
141 strlen( $body[
'text'] ) >= $minBodyLen &&
142 strlen( $body[
'html'] ) >= $minBodyLen
151 $body = $body[
'text'];
154 wfDebug( __METHOD__ .
': sending mail to ' . implode(
', ', $to ) .
"\n" );
157 $has_address =
false;
158 foreach ( $to as $u ) {
164 if ( !$has_address ) {
170 if ( count( $to ) > 1 ) {
173 if ( $oldTo != $to ) {
174 $splitTo = array_diff( $oldTo, $to );
175 $to = array_diff( $oldTo, $splitTo );
179 $status->merge( self::sendInternal(
180 $to, $from, $subject, $body, $options ) );
182 foreach ( $splitTo as $newTo ) {
183 $status->merge( self::sendInternal(
184 [ $newTo ], $from, $subject, $body, $options ) );
200 static $usable =
null;
201 if ( $usable ===
null ) {
202 $usable = class_exists(
'Mail_mime' );
214 static $usable =
null;
215 if ( $usable ===
null ) {
216 $usable = class_exists(
'Mail' );
248 $replyto = $options[
'replyTo'] ??
null;
249 $contentType = $options[
'contentType'] ??
'text/plain; charset=UTF-8';
250 $headers = $options[
'headers'] ?? [];
254 if ( !
Hooks::run(
'UserMailerTransformContent', [ $to, $from, &$body, &$error ] ) ) {
291 $headers[
'From'] = $from->
toString();
292 $returnPath = $from->address;
296 Hooks::run(
'UserMailerChangeReturnPath', [ $to, &$returnPath ] );
306 $returnPathCLI =
'"' . str_replace(
'"',
'', $returnPath ) .
'"';
307 $extraParams .=
' -f ' . $returnPathCLI;
309 $headers[
'Return-Path'] = $returnPath;
312 $headers[
'Reply-To'] = $replyto->toString();
317 $headers[
'X-Mailer'] =
'MediaWiki mailer';
325 if ( is_array( $body ) ) {
327 wfDebug(
"Assembling multipart mime email\n" );
328 if ( !self::isMailMimeUsable() ) {
329 wfDebug(
"PEAR Mail_Mime package is not installed. Falling back to text email.\n" );
331 $body = $body[
'text'];
335 $body[
'text'] = str_replace(
"\n",
"\r\n", $body[
'text'] );
336 $body[
'html'] = str_replace(
"\n",
"\r\n", $body[
'html'] );
338 $mime =
new Mail_mime( [
340 'text_charset' =>
'UTF-8',
341 'html_charset' =>
'UTF-8'
343 $mime->setTXTBody( $body[
'text'] );
344 $mime->setHTMLBody( $body[
'html'] );
345 $body = $mime->get();
346 $headers = $mime->headers( $headers );
349 if ( $mime ===
null ) {
352 $body = str_replace(
"\n",
"\r\n", $body );
354 $headers[
'MIME-Version'] =
'1.0';
355 $headers[
'Content-type'] = $contentType;
356 $headers[
'Content-transfer-encoding'] =
'8bit';
360 if ( !
Hooks::run(
'UserMailerTransformMessage',
361 [ $to, $from, &$subject, &$headers, &$body, &$error ] )
370 $ret =
Hooks::run(
'AlternateUserMailer', [ $headers, $to, $from, $subject, $body ] );
371 if ( $ret ===
false ) {
374 } elseif ( $ret !==
true ) {
381 if ( !self::isMailUsable() ) {
382 throw new MWException(
'PEAR mail package is not installed' );
385 $recips = array_map(
'strval', $to );
387 Wikimedia\suppressWarnings();
390 $mail_object = Mail::factory(
'smtp',
$wgSMTP );
391 if ( PEAR::isError( $mail_object ) ) {
392 wfDebug(
"PEAR::Mail factory failed: " . $mail_object->getMessage() .
"\n" );
393 Wikimedia\restoreWarnings();
396 '@phan-var Mail_smtp $mail_object';
398 wfDebug(
"Sending mail via PEAR::Mail\n" );
403 if ( count( $recips ) == 1 ) {
404 $headers[
'To'] = $recips[0];
410 foreach ( $chunks as $chunk ) {
414 Wikimedia\restoreWarnings();
418 Wikimedia\restoreWarnings();
422 if ( count( $to ) > 1 ) {
423 $headers[
'To'] =
'undisclosed-recipients:;';
427 wfDebug(
"Sending mail via internal mail() function\n" );
429 self::$mErrorString =
'';
430 $html_errors = ini_get(
'html_errors' );
431 ini_set(
'html_errors',
'0' );
432 set_error_handler(
'UserMailer::errorHandler' );
435 foreach ( $to as $recip ) {
444 }
catch ( Exception $e ) {
445 restore_error_handler();
449 restore_error_handler();
450 ini_set(
'html_errors', $html_errors );
452 if ( self::$mErrorString ) {
453 wfDebug(
"Error sending mail: " . self::$mErrorString .
"\n" );
455 } elseif ( !$sent ) {
457 wfDebug(
"Unknown error sending mail\n" );
472 self::$mErrorString = preg_replace(
'/^mail\(\)(\s*\[.*?\])?: /',
'', $string );
481 return strtr( $val, [
"\r" =>
'',
"\n" =>
'' ] );
493 $phrase = str_replace(
'"',
'', $phrase );
494 return '"' . $phrase .
'"';
512 if ( empty( $charset ) ) {
515 $charset = strtoupper( $charset );
516 $charset = str_replace(
'ISO-8859',
'ISO8859', $charset );
518 $illegal =
'\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\xff=';
519 $replace = $illegal .
'\t ?_';
520 if ( !preg_match(
"/[$illegal]/", $string ) ) {
523 $out =
"=?$charset?Q?";
524 $out .= preg_replace_callback(
"/([$replace])/",
526 return sprintf(
"=%02X", ord(
$matches[1] ) );