wp_mail

Send mail, similar to PHP's mail.

Description

wp_mail( (string|array) $to, (string) $subject, (string) $message, (string) $headers = '', (array) $attachments = array() ); 

A true return value does not automatically mean that the user received the email successfully. It just only means that the method used was able to process the request without any errors.

Using the two wp_mail_from and wp_mail_from_name hooks allow from creating a from address like Name when both are set. If just wp_mail_from is set, then just the email address will be used with no name.

The default content type is text/plain which does not allow using HTML. However, you can set the content type of the email by using the filter.

The default charset is based on the charset used on the blog. The charset can be set using the filter.

Parameters (5)

0. $to (string|array)
Array or comma-separated list of email addresses to send message.
1. $subject (string)
Email subject
2. $message (string)
Message contents
3. $headers — Optional. (string) => ''
Additional headers.
4. $attachments — Optional. (array) => array()
Files to attach.

Usage

  1. if ( !function_exists( 'wp_mail' ) ) { 
  2. require_once ABSPATH . WPINC . '/pluggable.php'; 
  3.  
  4. // Array or comma-separated list of email addresses to send message. 
  5. $to = null; 
  6.  
  7. // Email subject 
  8. $subject = ''; 
  9.  
  10. // Message contents 
  11. $message = ''; 
  12.  
  13. // Optional. Additional headers. 
  14. $headers = ''; 
  15.  
  16. // Optional. Files to attach. 
  17. $attachments = array(); 
  18.  
  19. // NOTICE! Understand what this does before running. 
  20. $result = wp_mail($to, $subject, $message, $headers, $attachments); 
  21.  

Defined (1)

The function is defined in the following location(s).

/wp-includes/pluggable.php  
  1. function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() ) { 
  2. // Compact the input, apply the filters, and extract them back out 
  3.  
  4. /** 
  5. * Filters the wp_mail() arguments. 
  6. * @since 2.2.0 
  7. * @param array $args A compacted array of wp_mail() arguments, including the "to" email,  
  8. * subject, message, headers, and attachments values. 
  9. */ 
  10. $atts = apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) ); 
  11.  
  12. if ( isset( $atts['to'] ) ) { 
  13. $to = $atts['to']; 
  14.  
  15. if ( isset( $atts['subject'] ) ) { 
  16. $subject = $atts['subject']; 
  17.  
  18. if ( isset( $atts['message'] ) ) { 
  19. $message = $atts['message']; 
  20.  
  21. if ( isset( $atts['headers'] ) ) { 
  22. $headers = $atts['headers']; 
  23.  
  24. if ( isset( $atts['attachments'] ) ) { 
  25. $attachments = $atts['attachments']; 
  26.  
  27. if ( ! is_array( $attachments ) ) { 
  28. $attachments = explode( "\n", str_replace( "\r\n", "\n", $attachments ) ); 
  29. global $phpmailer; 
  30.  
  31. // (Re)create it, if it's gone missing 
  32. if ( ! ( $phpmailer instanceof PHPMailer ) ) { 
  33. require_once ABSPATH . WPINC . '/class-phpmailer.php'; 
  34. require_once ABSPATH . WPINC . '/class-smtp.php'; 
  35. $phpmailer = new PHPMailer( true ); 
  36.  
  37. // Headers 
  38. $cc = $bcc = $reply_to = array(); 
  39.  
  40. if ( empty( $headers ) ) { 
  41. $headers = array(); 
  42. } else { 
  43. if ( !is_array( $headers ) ) { 
  44. // Explode the headers out, so this function can take both 
  45. // string headers and an array of headers. 
  46. $tempheaders = explode( "\n", str_replace( "\r\n", "\n", $headers ) ); 
  47. } else { 
  48. $tempheaders = $headers; 
  49. $headers = array(); 
  50.  
  51. // If it's actually got contents 
  52. if ( !empty( $tempheaders ) ) { 
  53. // Iterate through the raw headers 
  54. foreach ( (array) $tempheaders as $header ) { 
  55. if ( strpos($header, ':') === false ) { 
  56. if ( false !== stripos( $header, 'boundary=' ) ) { 
  57. $parts = preg_split('/boundary=/i', trim( $header ) ); 
  58. $boundary = trim( str_replace( array( "'", '"' ), '', $parts[1] ) ); 
  59. continue; 
  60. // Explode them out 
  61. list( $name, $content ) = explode( ':', trim( $header ), 2 ); 
  62.  
  63. // Cleanup crew 
  64. $name = trim( $name ); 
  65. $content = trim( $content ); 
  66.  
  67. switch ( strtolower( $name ) ) { 
  68. // Mainly for legacy -- process a From: header if it's there 
  69. case 'from': 
  70. $bracket_pos = strpos( $content, '<' ); 
  71. if ( $bracket_pos !== false ) { 
  72. // Text before the bracketed email is the "From" name. 
  73. if ( $bracket_pos > 0 ) { 
  74. $from_name = substr( $content, 0, $bracket_pos - 1 ); 
  75. $from_name = str_replace( '"', '', $from_name ); 
  76. $from_name = trim( $from_name ); 
  77.  
  78. $from_email = substr( $content, $bracket_pos + 1 ); 
  79. $from_email = str_replace( '>', '', $from_email ); 
  80. $from_email = trim( $from_email ); 
  81.  
  82. // Avoid setting an empty $from_email. 
  83. } elseif ( '' !== trim( $content ) ) { 
  84. $from_email = trim( $content ); 
  85. break; 
  86. case 'content-type': 
  87. if ( strpos( $content, ';' ) !== false ) { 
  88. list( $type, $charset_content ) = explode( ';', $content ); 
  89. $content_type = trim( $type ); 
  90. if ( false !== stripos( $charset_content, 'charset=' ) ) { 
  91. $charset = trim( str_replace( array( 'charset=', '"' ), '', $charset_content ) ); 
  92. } elseif ( false !== stripos( $charset_content, 'boundary=' ) ) { 
  93. $boundary = trim( str_replace( array( 'BOUNDARY=', 'boundary=', '"' ), '', $charset_content ) ); 
  94. $charset = ''; 
  95.  
  96. // Avoid setting an empty $content_type. 
  97. } elseif ( '' !== trim( $content ) ) { 
  98. $content_type = trim( $content ); 
  99. break; 
  100. case 'cc': 
  101. $cc = array_merge( (array) $cc, explode( ', ', $content ) ); 
  102. break; 
  103. case 'bcc': 
  104. $bcc = array_merge( (array) $bcc, explode( ', ', $content ) ); 
  105. break; 
  106. case 'reply-to': 
  107. $reply_to = array_merge( (array) $reply_to, explode( ', ', $content ) ); 
  108. break; 
  109. default: 
  110. // Add it to our grand headers array 
  111. $headers[trim( $name )] = trim( $content ); 
  112. break; 
  113.  
  114. // Empty out the values that may be set 
  115. $phpmailer->ClearAllRecipients(); 
  116. $phpmailer->ClearAttachments(); 
  117. $phpmailer->ClearCustomHeaders(); 
  118. $phpmailer->ClearReplyTos(); 
  119.  
  120. // From email and name 
  121. // If we don't have a name from the input headers 
  122. if ( !isset( $from_name ) ) 
  123. $from_name = 'WordPress'; 
  124.  
  125. /** If we don't have an email from the input headers default to wordpress@$sitename 
  126. * Some hosts will block outgoing mail from this address if it doesn't exist but 
  127. * there's no easy alternative. Defaulting to admin_email might appear to be another 
  128. * option but some hosts may refuse to relay mail from an unknown domain. See 
  129. * https://core.trac.wordpress.org/ticket/5007. 
  130. */ 
  131.  
  132. if ( !isset( $from_email ) ) { 
  133. // Get the site domain and get rid of www. 
  134. $sitename = strtolower( $_SERVER['SERVER_NAME'] ); 
  135. if ( substr( $sitename, 0, 4 ) == 'www.' ) { 
  136. $sitename = substr( $sitename, 4 ); 
  137.  
  138. $from_email = 'wordpress@' . $sitename; 
  139.  
  140. /** 
  141. * Filters the email address to send from. 
  142. * @since 2.2.0 
  143. * @param string $from_email Email address to send from. 
  144. */ 
  145. $from_email = apply_filters( 'wp_mail_from', $from_email ); 
  146.  
  147. /** 
  148. * Filters the name to associate with the "from" email address. 
  149. * @since 2.3.0 
  150. * @param string $from_name Name associated with the "from" email address. 
  151. */ 
  152. $from_name = apply_filters( 'wp_mail_from_name', $from_name ); 
  153.  
  154. $phpmailer->setFrom( $from_email, $from_name, false ); 
  155.  
  156. // Set destination addresses 
  157. if ( !is_array( $to ) ) 
  158. $to = explode( ', ', $to ); 
  159.  
  160. // Set mail's subject and body 
  161. $phpmailer->Subject = $subject; 
  162. $phpmailer->Body = $message; 
  163.  
  164. // Use appropriate methods for handling addresses, rather than treating them as generic headers 
  165. $address_headers = compact( 'to', 'cc', 'bcc', 'reply_to' ); 
  166.  
  167. foreach ( $address_headers as $address_header => $addresses ) { 
  168. if ( empty( $addresses ) ) { 
  169. continue; 
  170.  
  171. foreach ( (array) $addresses as $address ) { 
  172. try { 
  173. // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>" 
  174. $recipient_name = ''; 
  175.  
  176. if ( preg_match( '/(.*)<(.+)>/', $address, $matches ) ) { 
  177. if ( count( $matches ) == 3 ) { 
  178. $recipient_name = $matches[1]; 
  179. $address = $matches[2]; 
  180.  
  181. switch ( $address_header ) { 
  182. case 'to': 
  183. $phpmailer->addAddress( $address, $recipient_name ); 
  184. break; 
  185. case 'cc': 
  186. $phpmailer->addCc( $address, $recipient_name ); 
  187. break; 
  188. case 'bcc': 
  189. $phpmailer->addBcc( $address, $recipient_name ); 
  190. break; 
  191. case 'reply_to': 
  192. $phpmailer->addReplyTo( $address, $recipient_name ); 
  193. break; 
  194. } catch ( phpmailerException $e ) { 
  195. continue; 
  196.  
  197. // Set to use PHP's mail() 
  198. $phpmailer->IsMail(); 
  199.  
  200. // Set Content-Type and charset 
  201. // If we don't have a content-type from the input headers 
  202. if ( !isset( $content_type ) ) 
  203. $content_type = 'text/plain'; 
  204.  
  205. /** 
  206. * Filters the wp_mail() content type. 
  207. * @since 2.3.0 
  208. * @param string $content_type Default wp_mail() content type. 
  209. */ 
  210. $content_type = apply_filters( 'wp_mail_content_type', $content_type ); 
  211.  
  212. $phpmailer->ContentType = $content_type; 
  213.  
  214. // Set whether it's plaintext, depending on $content_type 
  215. if ( 'text/html' == $content_type ) 
  216. $phpmailer->IsHTML( true ); 
  217.  
  218. // If we don't have a charset from the input headers 
  219. if ( !isset( $charset ) ) 
  220. $charset = get_bloginfo( 'charset' ); 
  221.  
  222. // Set the content-type and charset 
  223.  
  224. /** 
  225. * Filters the default wp_mail() charset. 
  226. * @since 2.3.0 
  227. * @param string $charset Default email charset. 
  228. */ 
  229. $phpmailer->CharSet = apply_filters( 'wp_mail_charset', $charset ); 
  230.  
  231. // Set custom headers 
  232. if ( !empty( $headers ) ) { 
  233. foreach ( (array) $headers as $name => $content ) { 
  234. $phpmailer->AddCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) ); 
  235.  
  236. if ( false !== stripos( $content_type, 'multipart' ) && ! empty($boundary) ) 
  237. $phpmailer->AddCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $content_type, $boundary ) ); 
  238.  
  239. if ( !empty( $attachments ) ) { 
  240. foreach ( $attachments as $attachment ) { 
  241. try { 
  242. $phpmailer->AddAttachment($attachment); 
  243. } catch ( phpmailerException $e ) { 
  244. continue; 
  245.  
  246. /** 
  247. * Fires after PHPMailer is initialized. 
  248. * @since 2.2.0 
  249. * @param PHPMailer &$phpmailer The PHPMailer instance, passed by reference. 
  250. */ 
  251. do_action_ref_array( 'phpmailer_init', array( &$phpmailer ) ); 
  252.  
  253. // Send! 
  254. try { 
  255. return $phpmailer->Send(); 
  256. } catch ( phpmailerException $e ) { 
  257.  
  258. $mail_error_data = compact( 'to', 'subject', 'message', 'headers', 'attachments' ); 
  259. $mail_error_data['phpmailer_exception_code'] = $e->getCode(); 
  260.  
  261. /** 
  262. * Fires after a phpmailerException is caught. 
  263. * @since 4.4.0 
  264. * @param WP_Error $error A WP_Error object with the phpmailerException message, and an array 
  265. * containing the mail recipient, subject, message, headers, and attachments. 
  266. */ 
  267. do_action( 'wp_mail_failed', new WP_Error( 'wp_mail_failed', $e->getMessage(), $mail_error_data ) ); 
  268.  
  269. return false;