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 = 'your-email@gmail.com'
$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:img1@your-domain.com" /><br/>
More amazingly, <a href="cid:att1@your-domain.com">here</a> is a pdf.<br/>
And <a href="cid:att2@your-domain.com">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 = 'img1@your-domain.com'
$att.IsInline=$true
$att = $message.Attachments.AddFileAttachment($attachment1Path)
$att.ContentId = 'att1@your-domain.com'
$att.IsInline=$true
$att = $message.Attachments.AddFileAttachment($attachment2Path)
$att.ContentId = 'att2@your-domain.com'
$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: