Search code examples
perlemailmime

How can I refer to an attached image in an email built with Email::Stuffer?


I want to send an email with Email::Stuffer and refer to an attached image in the html part of the email. For that I'd need the MIME part with the image to have an ID, but I cannot get Email::Stuffer to add one.

#!perl
use strict;
use warnings;
use Email::Stuffer;

my $stuffer = Email::Stuffer
    ->from('me@example.org')
    ->to('you@example.org')
    ->subject('mcve')
    ->text_body('see attached image')
    ->attach_file('image.png');
print $stuffer->as_string(), "\n\n";

my @parts = $stuffer->email->subparts;
my $attachment = $parts[1];
my %headers = $attachment->header_str_pairs();
print "CID header: ", $headers{'Content-ID'}, "\n\n";

Oddly enough this prints something that looks like a content id, even though the mime structure it prints does not have the Content-ID header:

Date: Sat, 28 Oct 2023 10:33:05 -0500
MIME-Version: 1.0
From: me@example.org
To: you@example.org
Subject: mcve
Content-Transfer-Encoding: 7bit
Content-Type: multipart/mixed; boundary=16985071850.4fFe46cEc.181699


--16985071850.4fFe46cEc.181699
Date: Sat, 28 Oct 2023 10:33:05 -0500
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

see attached image=

--16985071850.4fFe46cEc.181699
Date: Sat, 28 Oct 2023 10:33:05 -0500
MIME-Version: 1.0
Content-Type: image/png; name=image.png
Content-Transfer-Encoding: base64
Content-Disposition: inline; filename=image.png

(some base64 data here)

--16985071850.4fFe46cEc.181699--


CID header: <16985071854.8a407.181699@perle>

It doesn't make a difference if I print after querying the content id header, so asking for one doesn't magically add it.

When I use attach_file('image.png', 'Content-ID' => 'my@id'); instead of plain attach, it adds a content-id attribute to the content-type header like this: Content-Type: image/png; content-id=my@id; name=image.png.

I've tried to manually add a header to the image part

$headers{'Content-ID'} = $cid;
$attachment->header_str_set('Content-ID' => [$cid]);

but when I print the email as text, the Content-ID header still does not show up.

How can I get Email::Stuffer to add the Content-ID header to the image part?


Solution

  • How can I get Email::Stuffer to add the Content-ID header to the image part?

    I did some debugging and the following modification of your script seems to work:

    • Instead of using $stuffer->email->subparts, use $stuffer->parts
    • Instead of using $attachment->header_str_set('Content-ID' => [$cid]);, use $attachment->header_set('Content-ID', $cid);

    Example:

    # ... Previous part of script as before...
    my @parts = $stuffer->parts;
    my $attachment = $parts[1];
    $attachment->header_set('Content-ID', "<image.png>");
    print $stuffer->as_string(), "\n\n";
    

    Output:

    [...]
    Date: Sat, 28 Oct 2023 23:29:04 +0200
    MIME-Version: 1.0
    Content-Type: image/png; name=image.png
    Content-Transfer-Encoding: base64
    Content-Disposition: inline; filename=image.png
    Content-ID: <image.png>
    
    [...]