Title: using wp_mail with php-generated attachments
Last modified: August 20, 2016

---

# using wp_mail with php-generated attachments

 *  [panda47](https://wordpress.org/support/users/panda47/)
 * (@panda47)
 * [13 years, 3 months ago](https://wordpress.org/support/topic/using-wp_mail-with-php-generated-attachments/)
 * hello,
 * TLDR version – I had some problem sending e-mails with on-the-fly generated attachments,
   so here’s what I was trying to do and how I fixed it (end of TLDR)
 * I am currently working for non-profit organization and I had to deploy simple
   form on one of our websites running WP.
 * The funny thing to do was generating PDF of what the user posted in the form 
   and sending this PDF as an e-mail attachment to him.
 * long story short – as a form input we use si-contact-form ([http://wordpress.org/extend/plugins/si-contact-form/](http://wordpress.org/extend/plugins/si-contact-form/))
   
   and to generate PDFs I chose FPDF ([http://www.fpdf.org/](http://www.fpdf.org/)).
 * FPDF allows me to pass the pdf as a string with
    `$string = $pdf->Output("filename-
   this_is_ignored_when_i_want_string", "S");` and then I wanted to add that as 
   an attachment. unfortunatelly wp_mail doesn’t support adding string attachments,
   although it uses phpmailer, which itself has this feature `AddStringAttachment(
   $string,$filename,$encoding,$type);`
 * So I had to add it manually – in a body part of the message, and of course set
   the content-type header to multipart/mixed…
 *     ```
       $semirandom = md5(time());
               $header .= 'Content-Type: multipart/mixed; boundary=' . $semirandom . "\r\n";
   
               $message = "--".$semirandom."\r\n";
   
       	$message .= 'Content-type: text/html; charset='. get_option('blog_charset') . $php_eol;
       	//$msg is previously generated message from what admin of the site specifies
               $message .= "\r\n".$msg."\r\n\r\n";
   
               $message .= "--".$semirandom."\r\n";
   
               $message .= "Content-Type: application/octet-stream; name=\"form.pdf\"\r\n";
               $message .= "Content-Disposition: attachment; filename=\"form.pdf\"\r\n";
               $message .= "Content-Transfer-Encoding: base64\r\n\r\n";
               $message .= chunk_split(base64_encode($pdf->Output("","S")));
   
               $message .= "--".$semirandom."--";
   
               @wp_mail($email, $subj, $message, $header);
       ```
   
 * which worked fine in almost everything (gmail and yahoo etc. throung webbrowsers,
   some company mail servers with thunderbird/outlook…)
    until my friend tried it
   with his university e-mail account forwarded to gmail, which instead of text 
   displayed the actual stuff I put in $message
 *     ```
       --8d5ae687d4dacb540c7bde17ab5e7fef
       Content-type: text/html; charset=UTF-8
   
       hello,
       blah blah text of the e-mail
   
       --8d5ae687d4dacb540c7bde17ab5e7fef
       Content-Type: application/octet-stream; name="form.pdf"
       Content-Disposition: attachment; filename="form.pdf"
       Content-Transfer-Encoding: base64
   
       go8PC9UeXBlIC9QYWdlCi9QYXJlbnQgMSAwIFIKL1Jlc291cmNlcyAy
       IDAgUgovQ29udGVudHMgNCAwIFI+PgplbmRvYmoKNCA... (encoded PDF)
       --8d5ae687d4dacb540c7bde17ab5e7fef--
       ```
   
 * So I had to dig. As it turns out, the message had two “content-type: multipart/
   mixed” headers like this:
 *     ```
       Content-Type: multipart/mixed;
       	 boundary="5b34d68abe22d374e2af04c6783370f2"
       MIME-Version: 1.0
       Content-Transfer-Encoding: 8bit
       Content-Type: multipart/mixed; charset=""
       ```
   
 * the first one (that one with boundary, which is !before! MIME-Version: 1.0) is
   the one I inserted, the second one was inserted by wp_mail().
    And this is not
   what we want, even if most of mailservers and clients did not have problem with
   it…
 * I found the problem in pluggable.php somewhere around line 410:
 *     ```
       // Set Content-Type and charset
       	// If we don't have a content-type from the input headers
       	if ( !isset( $content_type ) )
       		$content_type = 'text/plain';
   
       	$content_type = apply_filters( 'wp_mail_content_type', $content_type );
   
       	$phpmailer->ContentType = $content_type;
   
       	// Set whether it's plaintext, depending on $content_type
       	if ( 'text/html' == $content_type )
       		$phpmailer->IsHTML( true );
       	// If we don't have a charset from the input headers
       	if ( !isset( $charset ) )
       		$charset = get_bloginfo( 'charset' );
   
       	// Set the content-type and charset
       	$phpmailer->CharSet = apply_filters( 'wp_mail_charset', $charset );
   
       	// Set custom headers
       	if ( !empty( $headers ) ) {
       		foreach( (array) $headers as $name => $content ) {
       			$phpmailer->AddCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) );
       		}
       	if ( false !== stripos( $content_type, 'multipart' ) && ! empty($boundary) )
       			$phpmailer->AddCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $content_type, $boundary ) );
       	}
       ```
   
 * this code sets the multipart/mixed twice – first one is the `$phpmailer->ContentType
   = $content_type;` line, which makes that header below “MIME-Version: 1.0”, but
   without boundary
 * and the second one is the last line of this snippet, which adds it with boundary,
   but as a custom header which is placed before “MIME-Version: 1.0”
 * so a quick fix for me looks like this – it sets the boundary right to to $phpmailer-
   >ContentType and I deleted the second part which adds it as custom header
 *     ```
       //fixed by Martin Svetlik
       	if ( false !== stripos( $content_type, 'multipart' ) && ! empty($boundary) ) {
       		$phpmailer->ContentType = $content_type . "; boundary=" . $boundary;
       	}
       	else {
       		$phpmailer->ContentType = $content_type;
   
       		// Set whether it's plaintext, depending on $content_type
       		if ( 'text/html' == $content_type )
       			$phpmailer->IsHTML( true );
   
       		// If we don't have a charset from the input headers
       		if ( !isset( $charset ) )
       			$charset = get_bloginfo( 'charset' );
       	}
       //end of the fix
   
       	// Set the content-type and charset
       	$phpmailer->CharSet = apply_filters( 'wp_mail_charset', $charset );
   
       	// Set custom headers
       	if ( !empty( $headers ) ) {
       		foreach( (array) $headers as $name => $content ) {
       			$phpmailer->AddCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) );
       		}
       /*		//M.S. deteled this - it's set it several rows up
       		if ( false !== stripos( $content_type, 'multipart' ) && ! empty($boundary) )
       			$phpmailer->AddCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=%s", $content_type, $boundary ) );
       */	}
       ```
   
 * this works pretty good, but produces header with “charset” even for multipart
   messages like
 *     ```
       MIME-Version: 1.0
       Content-Transfer-Encoding: 8bit
       Content-Type: multipart/mixed; boundary=3432f0f547aafa6045243aba478151d3; charset=""
       ```
   
 * and it’s not much user-friendly.
 * so the ultimate sollution was to add function to work with string attachments–
   
   the function wp_mail in pluggable.php is now declared as `function wp_mail( $
   to, $subject, $message, $headers = '', $attachments = array(), $string_attachments
   = array() )`
 * and at the end, where normal attachments are added is my new part which adds 
   string attachments, so it looks like this
 *     ```
       if ( !empty( $attachments ) ) {
       		foreach ( $attachments as $attachment ) {
       			try {
       				$phpmailer->AddAttachment($attachment);
       			} catch ( phpmailerException $e ) {
       				continue;
       			}
       		}
       	}
   
       //added this. Martin Svetlik
       	if ( !empty( $string_attachments ) ) {
       		foreach ( $string_attachments as $str_attachment ) {
       			try {
       				$phpmailer->AddStringAttachment($str_attachment[0], $str_attachment[1], $str_attachment[2], $str_attachment[3]);
       			} catch ( phpmailerException $e ) {
       				continue;
       			}
       		}
       	}
       ```
   
 * and it is used like this
 *     ```
       $str_att1 = array();
       	$str_att1[0] = $pdf->Output("","S");
       	$str_att1[1] = "F3_registracia.pdf";
       	$str_att1[2] = "base64";
       	$str_att1[3] = "application/octet-stream";
   
       	$string_att_array = array();
       	$string_att_array[] = $str_att1;
   
       	@wp_mail($email, $subj, $msg, $header, $normal_attachments, $string_att_array);
       ```
   
 * hope this helps if somebody has the same problem, and maybe even maked into next
   version of WP 🙂

The topic ‘using wp_mail with php-generated attachments’ is closed to new replies.

 * In: [Hacks](https://wordpress.org/support/forum/plugins-and-hacks/hacks/)
 * 0 replies
 * 1 participant
 * Last reply from: [panda47](https://wordpress.org/support/users/panda47/)
 * Last activity: [13 years, 3 months ago](https://wordpress.org/support/topic/using-wp_mail-with-php-generated-attachments/)
 * Status: not resolved

## Topics

### Topics with no replies

### Non-support topics

### Resolved topics

### Unresolved topics

### All topics
