是否可以像 Outlook RTF/TNEF 那样在 html 电子邮件中嵌入非图像附件?

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

当您使用 Outlook 发送电子邮件时,您可以选择 RTF 格式而不是 HTML,这样您就可以在电子邮件正文中内嵌 PDF 等附件。当您附加多个文件并希望在正文中引用它们时,这会非常方便。如果您在 Outlook 中选择 HTML 格式,这将不再可行,并且附加图像会出现在电子邮件正文之外(如 'normal')。

我正在以编程方式发送电子邮件,想知道是否可以通过某种方式将附件嵌入到电子邮件正文中。 You can do this with images,使用类似 <img src="cid:image_id@somethingorother" /> 的标签来引用多部分电子邮件中的嵌入图像。有没有办法对其他类型的附件执行此操作?

我主要对这样一种情况感兴趣:我使用 Outlook 作为邮件客户端,向所有位于同一 MS Exchange 电子邮件服务器上的收件人发送电子邮件。有时他们会使用不同的电子邮件客户端,或从外部发送,如果在这种情况下电子邮件降级为 'normal' 个附件,那也没关系。

我也可以使用 RTF/TNEF 格式,但是:

我决定少偷懒,自己试试...

答案是,您可以使用<a href='cid:...'> . </a> 标记在html 电子邮件中引用非图像附件,Outlook 将打开它们。我使用 Outlook 2013 作为我的电子邮件客户端和 Office365 作为我的服务器;里程因不同的客户端和服务器而异。 但是如果你不使用 outlook 就不太好用了...

Gmail

我也测试了发送到 gmail。内联图像工作正常,但附件不行。 <a> link 显示但不起作用,如果您在电子邮件正文中使用 cid:... url 引用附件,gmail 不会显示它甚至与 disposition:attachment :( Gmail iPhone 应用程序上的行为相同:内联图像看起来很好,内联附件不显示或从 <a> links 打开。

iPhone 邮件

iPhone 的邮件应用(连接到 Office 365)将 <a> 标签呈现为 link,但它们不起作用。如果您将附件配置设置为 'attachment'(即不是 'inline'),那么附件将显示在电子邮件的底部,不像 gmail 在这种情况下隐藏它们。如果您将附件配置设置为 'inline',那么它会隐藏附件。

所以如果你有 gmail recipients/email 客户端,你需要做一些不同的事情,甚至可能附加文件两次:一次作为 disposition:inline(linked 到正文中)一次是 disposition:attachment。令人遗憾的是,Gmail 不显示具有 disposition:attachment 并使用 cid 引用的附件,因为这至少意味着有一种方法可以访问它们。如果有人有任何建议,请告诉我!

示例代码

这是我用于测试的 powershell,使用 EWS。它发送 html 电子邮件

  • 嵌入图像(永远不会显示为 'an attachment')
  • a .pdf linked 带有 <a> 标签,标记为内联。在 Outlook 中,这不会显示为附件,但可以从 link 访问。在 gmail 和 iOS Mail 中,这不会显示为附件,也无法从 link.
  • 访问
  • 一个 .docx 文件 link 带有 <a> 标签并标记为附件。在 Outlook 中,这显示为附件,也可以从 link 访问。在 gmail 中,这不会显示并且在 link 中不起作用。在 iOS 邮件中,这显示为附件,但无法从 link.
  • 访问
  • 相同的 .docx 文件再次标记为附件,而不是 link 使用 <a> 标记编辑。这在 Outlook、gmail、iOS 邮件中作为附件可见。

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.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()

还有一些方便的文章: