Make WordPress Core

Opened 12 years ago

Closed 4 months ago

Last modified 2 months ago

#28059 closed enhancement (fixed)

Inline image attachments with wp_mail()

Reported by: jesin's profile jesin Owned by: sirlouen's profile SirLouen
Milestone: 6.9 Priority: normal
Severity: normal Version:
Component: Mail Keywords: has-patch has-test-info has-unit-tests add-to-field-guide commit has-dev-note
Focuses: Cc:

Description

To insert inline images in an email the phpmailer_init action hook has to be used like this.

add_action( 'phpmailer_init', 'embed_images' );

function embed_images( &$phpmailer ) {
    $phpmailer->AddEmbeddedImage( '/path/to/image1.png', 'image1.png' );
    $phpmailer->AddEmbeddedImage( '/path/to/image2.png', 'image2.png' );
    $phpmailer->AddEmbeddedImage( '/path/to/image3.png', 'image3.png' );
}

Why not implement this in wp_mail() itself?

Attachments (2)

28059.diff (1.8 KB) - added by jesin 12 years ago.
Add inline images using wp_mail()
28059.2.diff (1.9 KB) - added by jesin 10 years ago.
Update 28059.diff

Download all attachments as: .zip

Change History (45)

@jesin
12 years ago

Add inline images using wp_mail()

#1 @jesin
12 years ago

  • Keywords has-patch needs-testing added

#2 @chriscct7
10 years ago

  • Keywords needs-refresh added

@jesin
10 years ago

Update 28059.diff

#3 follow-up: @swissspidy
10 years ago

  • Keywords needs-unit-tests added; needs-refresh removed

According to the docs, $phpmailer->addEmbeddedImage is only useful for HTML messages. What happens when you use that in a text email?

#4 in reply to: ↑ 3 @jesin
10 years ago

Replying to swissspidy:

According to the docs, $phpmailer->addEmbeddedImage is only useful for HTML messages. What happens when you use that in a text email?

In a text message the email client shows the image as an attachment. I tested this on Gmail and Outlook.com.

#5 follow-up: @chris@…
10 years ago

I'm not sure if this is needed at the wp_mail level or not (although I needed to do the workaround today) but if this gets refreshed I wouldn't blindly assume that basename( $embed ) is valid for the $cid parameter.

Most people probably have image-1.png and image-2.png but it could be http://example.com/cats/logo.png and http://example.com/dogs/logo.png and basename() would turn them both into logo.png.

This ticket was mentioned in PR #9038 on WordPress/wordpress-develop by @SirLouen.


8 months ago
#6

After 10 years of this patch I still find this relevant, so I'm refreshing it

Following the advice of @chrisvendiadvertisingcom, I've added an improved way to have unique cids with md5

In the next message, I will be providing some testing info

Trac ticket: https://core.trac.wordpress.org/ticket/28059

#7 in reply to: ↑ 5 @SirLouen
8 months ago

  • Keywords has-test-info needs-dev-note added

Testing Instructions

  1. First, you need to set up a working Mail environment:
  • You might use some env like Local WP, Laravel Herd, FlyEnv, or the liking, all come with Mail testing system
  • Or if you are using wordpress-develop you might try to configure my PR 8555 which adds Mailhog support
  1. Secondly, you need to install some WP plugin (or add some code), to connect to the email delivery server. You might use some plugins like WP Mail SMTP and configure with the hostname and port of your Mail testing service.
  1. Once you have the mailing system completely setup, it's time to use my testing plugin: https://raw.githubusercontent.com/SirLouen/wp-mail-embed-showcase/refs/tags/1.0.0/wp-mail-embed-showcase.php
  • You can check the code and adapt it to your needs, in order to add whatever extra tests you would like to do.
  • By default, it adds a menu called Mail Embed Showcase, which will send an email with two default embeds: A PNG and an SVG using the filter hook wp_mail_embed_args to specify the SVG file type image/svg+xml (not defaulted by PHPMailer).
  1. Finally, if everything is OK, you will receive an email with the two embedded images showing.

@mukesh27 commented on PR #9038:


8 months ago
#8

The unit tests are going failed that needs to fixed.

This ticket was mentioned in Slack in #core-test by sirlouen. View the logs.


8 months ago

#10 @yashjawale
8 months ago

Test Report

Description

This report validates whether the indicated patch works as expected.

Patch tested: https://github.com/WordPress/wordpress-develop/pull/9038.diff

Environment

  • WordPress: 6.8.1
  • PHP: 8.2.27
  • Server: nginx/1.26.1
  • Database: mysqli (Server: 8.0.35 / Client: mysqlnd 8.2.27)
  • Browser: Chrome 138.0.0.0
  • OS: macOS
  • Theme: Twenty Twenty-Five 1.2
  • MU Plugins: None activated
  • Plugins:
    • Test Reports 1.2.0
    • WP Mail Embed Showcase 1.0.0 [SirLouen's testing plugin from comment:7]
    • WP Mail SMTP 4.5.0

Actual Results

  1. ✅ Able to embed the following mimetypes:
  • image/svg+xml
  • image/png
  • image/jpeg
  • image/gif
  • video/mp4
  • video/quicktime
  • audio/mpeg

Supplemental Artifacts

Before patch:
https://files.catbox.moe/6bccrs.png

After patch:
https://files.catbox.moe/wul6zc.png

#11 @iamadisingh
8 months ago

Test Report

Description

This report validates whether the indicated patch works as expected.

Patch tested: https://github.com/WordPress/wordpress-develop/pull/9038

Environment

  • WordPress: 6.8.1
  • PHP: 8.2.27
  • Server: nginx/1.26.1
  • Database: mysqli (Server: 8.0.35 / Client: mysqlnd 8.2.27)
  • Browser: Chrome 138.0.0.0
  • OS: macOS
  • Theme: Twenty Twenty-Five 1.2
  • MU Plugins: None activated
  • Plugins:
    • Test Reports 1.2.0
    • WP Mail Embed Showcase 1.0.0
    • WP Mail SMTP 4.5.0

Actual Results

  1. ✅ Issue resolved with patch.

Additional Notes

Supplemental Artifacts

Before Patch Screenshot: https://ibb.co/pBfx4NBr
After Patch Screenshot: https://ibb.co/Z6w1ZYyW

#12 @SirLouen
8 months ago

  • Keywords has-unit-tests added; needs-testing needs-unit-tests removed

This ticket was mentioned in Slack in #core by sirlouen. View the logs.


7 months ago

This ticket was mentioned in Slack in #core by sirlouen. View the logs.


7 months ago

#15 @SirLouen
6 months ago

  • Milestone set to 6.9

#16 @TimothyBlynJacobs
6 months ago

I think this would need some inline docs talking about how to actually use embeds in your HTML. As is, you have to read the source to figure out what cid you should use.

Should we allow providing a cid in the embeds parameter? Perhaps as the array key?

#17 @SirLouen
6 months ago

  • Keywords needs-unit-tests added; has-unit-tests removed
  • Owner set to SirLouen
  • Status changed from new to assigned

@TimothyBlynJacobs I get your point, but I'm not confident where do you think it would be best to put the inline docs for this? I've added some docs to both the function and the filter, check if this is what you mean.

Should we allow providing a cid in the embeds parameter? Perhaps as the array key?

This is why I introduced the filter hook, you can edit there the CID you want if you are willing to modify this without having to modify the signature.

What I'm noticing now, is that $embed_path is being sent twice. I'm going to fix this.

And definitely I think that this needs better unit tests.

#18 @SirLouen
6 months ago

  • Keywords has-unit-tests add-to-field-guide added; needs-dev-note needs-unit-tests removed

Adding the Unit Tests. This patch is completely ready to be shipped now.

#20 follow-up: @TimothyBlynJacobs
6 months ago

Thanks for putting the dev note together @SirLouen!

Looking at the example usages has really solidified the need to have predictable CID values. Since the path to the file is going to be dynamic, not being able to write the template value with a fixed CID means you have to do that interpolation you are showing in the example. I know there is a filter available, but needing to add and then remove a filter around your wp_mail call is awkward. A developer shouldn't need to use a filter to accomplish what looks like will be the common case.

Let's try a different signature where the cid value is the array key. I don't think we need to support the same new line parsing, or array conversion that we do for the headers parameter for instance.

#21 in reply to: ↑ 20 @SirLouen
6 months ago

Replying to TimothyBlynJacobs:

Looking at the example usages has really solidified the need to have predictable CID values. Since the path to the file is going to be dynamic, not being able to write the template value with a fixed CID means you have to do that interpolation you are showing in the example. I know there is a filter available, but needing to add and then remove a filter around your wp_mail call is awkward. A developer shouldn't need to use a filter to accomplish what looks like will be the common case.

Ok, I see your point

Let's try a different signature where the cid value is the array key. I don't think we need to support the same new line parsing, or array conversion that we do for the headers parameter for instance.

Yes, this simplifies a lot the CID generation. To be sincere, I opted into the safe side because it seems that in the MIME cid "literature", using MD5 is a popular practice. Technically, this approach should not cause collisions, but it looks so simple that there could be an edge case I can't think of. Although, logically, it feels safe.

Anyway, I've adapted everything to this simpler cid version because it looks better.

This is the updated version of my testing plugin

#22 follow-up: @TimothyBlynJacobs
6 months ago

Thanks @SirLouen! I've made a couple of tweaks. Will plan on committing later today or tomorrow.

#23 in reply to: ↑ 22 @SirLouen
6 months ago

Replying to TimothyBlynJacobs:

Thanks @SirLouen! I've made a couple of tweaks. Will plan on committing later today or tomorrow.

I was reviewing the inline docs, and I forgot that, since it was intended to be a replica of the attachments version it's also possible to add a string, which happens to get converted into a simple array with regular numeric keys. So I've added an extra unit test for this, just to make sure that both versions are always respected.

#24 @TimothyBlynJacobs
6 months ago

  • Resolution set to fixed
  • Status changed from assigned to closed

In 60698:

Mail: Support inline attachments.

MIME allows for referencing included attachments by their Content-ID header using the cid URL scheme. This can be used to embed images inline to the HTML message. For example, <img src="cid:logo">, will display the contents of message part with the Content-Id: <logo> header.

The wp_mail() function now supports including inline attachments through a new $embeds parameter. It accepts a map of Content-ID values to file paths. The wp_mail_embed_args filter can be used to customize the resulting PHPMailer::addEmbeddedImage method call.

Props jesin, swissspidy, chrisvendiadvertisingcom, SirLouen, mukesh27, yashjawale, iamadisingh.
Fixes #28059.

#26 @SergeyBiryukov
6 months ago

In 60699:

Tests: Remove redundant @covers tags in wp_mail() tests.

@covers has already been added at the class level, so there is no need to add it to individual unit tests.

Follow-up to [54702], [60698].

Props mukesh27.
See #28059.

@SergeyBiryukov commented on PR #9690:


6 months ago
#27

Thanks for the PR! Merged in r60699.

#28 follow-up: @jorbin
6 months ago

  • Resolution fixed deleted
  • Status changed from closed to reopened

The dev note on this mentions multiple different ways that $embed can be structured

With the last parameter being the path to each of the images intended to be embedded in the email, in the format of a string separated with a new line per path, a simple array of path strings, or an associative array, where the key will be the Content-ID.

The automated tests don't test all three of these, just two. Either the automated tests should cover all three of these options, or (better yet) this should be simplified so that $embeds takes in less formats (see: decisions, not options)

#29 in reply to: ↑ 28 @SirLouen
6 months ago

Replying to jorbin:

The automated tests don't test all three of these, just two. Either the automated tests should cover all three of these options, or (better yet) this should be simplified so that $embeds takes in less formats (see: decisions, not options)

Double check this: One test covers two, and the other covers the third.

#30 @jorbin
6 months ago

@SirLouen Thanks, I missed the canola. This could be made a bit easier to read and be more fully tested if it used a dataprovider and associative, indexed, and mixed arrays.

Further, removing the acceptance of a string would make this simpler. While $attachments accepts both, the considerations in 2008 when it was added were not around type safety.

This ticket was mentioned in PR #9764 on WordPress/wordpress-develop by @SirLouen.


5 months ago
#31

This PR improves the unit tests providing the 3 potential scenarios with arrays, mixed, associative and index arrays as suggested by @jorbin

#32 @SirLouen
5 months ago

  • Keywords commit added

Ok @jorbin I've added the data provider to the test.

For the string part, we should be accepting a single path without an array for the minimal case scenario, which is very convenient.
In this case, adding the equivalence with attachments improves cohesiveness, and the increase in code is minimal (exploding vs. not exploding). Someone already using the old version of attachments will pick this up fast, and given how many reviews this has already had, this will be better kept as is.

#33 @SirLouen
5 months ago

  • Keywords has-dev-note added

This ticket was mentioned in Slack in #core by welcher. View the logs.


4 months ago

This ticket was mentioned in Slack in #core by welcher. View the logs.


4 months ago

#36 @wildworks
4 months ago

@SirLouen @jorbin If I understand correctly, the remaining task to be addressed in this ticket is improving the unit tests. Is that correct? If so, do you think we can commit that even after the 6.9 Beta release?

@jorbin commented on PR #9764:


4 months ago
#37

@dmsnell The wrapping is so that it passes it as an array and not as three strings. The renaming looks good though

#38 @jorbin
4 months ago

  • Resolution set to fixed
  • Status changed from reopened to closed

In 61025:

Mail: Improve tests for mail embeds

Use a dataProvider to ensure that embeds works with multiple different shaped arrays.

Follow-up to [60698].

Props sirlouen, dmsnell, jorbin.
Fixes #28059.

@dmsnell commented on PR #9764:


4 months ago
#39

thanks @aaronjorbin — I see that now. I guess I removed the inner array too, which should have stayed. thanks for following-up on it!

#40 @desrosj
3 months ago

The miscellaneous developer-focused changes developer note mentioned the new wp_mail_embed_args hook introduced in [60698], but did not cover it's usage in depth because of the previous dev note: https://make.wordpress.org/core/2025/11/17/miscellaneous-developer-focused-changes-in-6-9/.

#41 @westonruter
2 months ago

In 61352:

Mail: Add missing embeds key for the wp_mail_succeeded action's $mail_data param.

Follow-up to [60698].

Props iflairwebtechnologies, SirLouen, johnbillion.
See #28059.
Fixes #64348.

#42 @johnbillion
2 months ago

In 61386:

Mail: Update some docblocks relating to inline email attachments.

See #28059, #64224

#43 @peterwilsoncc
2 months ago

In 61393:

Mail: Add missing embeds key for the wp_mail_succeeded action's $mail_data param.

Follow-up to [60698].

Reviewed by peterwilsoncc.
Merges [61352] to the 6.9 branch.

Props iflairwebtechnologies, SirLouen, johnbillion, westonruter.
See #28059.
Fixes #64348.

Note: See TracTickets for help on using tickets.