Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to embed non-image attachments inline in an html email, like Outlook RTF/TNEF does?

When you send an email using Outlook you can choose RTF format instead of HTML, allowing you to embed attachments like PDFs inline within the email body. This can be very handy when you're attaching several files and wanting to refer to them within the body. If you choose HTML format in Outlook this is no longer possible and attached images appear outside the body of the email (like 'normal').

I'm sending emails programmatically and want to know if it's possible to embed attachments inline within the email body somehow. You can do this with images, using a tag like <img src="cid:image_id@somethingorother" /> referring to an embedded image within the multipart email. Is there a way to do this with other types of attachments?

I'm primarily interested in a scenario where I'm sending emails to recipients who are all on the same MS Exchange email server, using Outlook as their mail client. Sometimes they'll be using a different email client, or sent externally, and it's ok if the email degrades in such cases to 'normal' attachments.

I could alternatively use the RTF/TNEF format, but:

  • that seems hard, and
  • the content of my emails is in html, so I'd first have to convert RTF to HTML.
like image 737
Rory Avatar asked May 08 '15 22:05

Rory


People also ask

How do you inline an attachment in Outlook?

On the File menu, click New, and then click Mail Message. On the Message tab, in the Include group, click Attach File. In the Insert File dialog box, browse to and choose the file that you want to attach, and then click Insert.


1 Answers

I decided to be less lazy and try it myself...

The answer is yes, you can refer to non-image attachments within an html email using an <a href='cid:...'> . </a> tag and Outlook will open them. I'm using Outlook 2013 as my email client and Office365 as my server; mileage varies with different clients and maybe servers. But doesn't work so well if you don't use outlook...

Gmail

I tested sending to gmail too. Inline images work fine, but attachments don't. The <a> links are displayed but don't work, and if you refer to an attachment using a cid:... url within the body of the email gmail doesn't display it even with disposition:attachment :( Same behavior on the gmail iPhone app: inline images look fine, inline attachments don't display or open from <a> links.

iPhone Mail

iPhone's Mail app (connecting to Office 365) renders the <a> tags as links but they don't work. If you set the attachment disposition to 'attachment' (i.e. not 'inline') then the attachments are displayed at the bottom of the email, unlike gmail which hides them in this case. If you set attachment disposition to 'inline' then it hides the attachments.

So if you have gmail recipients/email clients you'll need to do something differently, perhaps even attaching files twice: once as disposition:inline (linked to within the body) and once as disposition:attachment. It's sad that Gmail doesn't display attachments that have disposition:attachment and are referred to using the cid, since that would at least mean there's a way to access them. If anyone has any suggestions do let me know!

Sample code

Here's the powershell I used for testing, using EWS. It sends an html email with

  • an embedded image (which never appears as 'an attachment')
  • a .pdf linked to with an <a> tag, marked as inline. In Outlook this doesn't appear as an attachment but can be accessed from the link. In both gmail and iOS Mail this isn't shown as an attachment and can't be accessed from the link.
  • a .docx file linked with an <a> tag and marked as an attachment. In Outlook this appears as an attachment and also can be accessed from the link. In gmail this isn't shown and doesn't work from the link. In iOS Mail this is shown as an attachment but can't be accessed from the link.
  • the same .docx file again marked as attachment and not linked with <a> tag. This is visible in Outlook, gmail, iOS Mail as an attachment.

powershell:

$to1 = '[email protected]'
$to2 = 'your-email@your-domaincom'
$subject = 'Test email with embedded attachments'
$body = '
This email shows embedded attachments. Yay. <br/><br/>
Here is an image: <img src="cid:[email protected]" /><br/>
More amazingly, <a href="cid:[email protected]">here</a> is a pdf.<br/>
And <a href="cid:[email protected]">here</a> is a word doc!<br/><br/>
'
# fyi - the '@your-domain.com' in the id is optional but somewhere I read 
# that email clients might like it more if it's included. Doesn't need to 
# be a real domain.

# change these paths to something that exists
$image1Path = "C:\temp\an_image.jpg"
$attachment1Path = "C:\temp\some_file.pdf"
$attachment2Path = "C:\temp\some_doc.docx"

#prompt for Office365 creds
$Credential = Get-Credential

#Load the EWS Managed API Assembly - you need it installed first!!
Add-Type -Path 'C:\Program Files (x86)\Microsoft\Exchange\Web Services\2.1\Microsoft.Exchange.WebServices.dll'

#Instantiate the EWS service object                  
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService

#Set the credentials for Exchange Online
$service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials -ArgumentList  $Credential.UserName, $Credential.GetNetworkCredential().Password

#Autodiscover doesn't seem to work for my office365; set it manually
$service.Url = 'https://outlook.office365.com/EWS/Exchange.asmx'
#This might work for you instead: 
# $service.AutodiscoverUrl($Credential.UserName, {$true})

#Create the email message and set the Subject and Body
$message = New-Object Microsoft.Exchange.WebServices.Data.EmailMessage -ArgumentList $service
$message.Subject = $subject
$message.Body = $body
$null = $message.ToRecipients.Add($to1)
$null = $message.ToRecipients.Add($to2)
$att = $message.Attachments.AddFileAttachment($image1Path)
$att.ContentId = '[email protected]'
$att.IsInline=$true
$att = $message.Attachments.AddFileAttachment($attachment1Path)
$att.ContentId = '[email protected]'
$att.IsInline=$true
$att = $message.Attachments.AddFileAttachment($attachment2Path)
$att.ContentId = '[email protected]'
$att.IsInline=$false

# add the same attachment again with a different name to see if it's 
# rendered differently.
$att = $message.Attachments.AddFileAttachment('no_cid.docx', $attachment2Path)
$att.IsInline=$false

#Send the message and save a copy in the Sent Items folder
$message.SendAndSaveCopy()

And some handy articles:

  • Send Email from Exchange Online by Using PowerShell
  • Adding inline attachments by using the EWS Managed API 2.0
like image 65
Rory Avatar answered Nov 02 '22 03:11

Rory