Excel VBA 创建 Outlook 邮件时,如何解决内嵌图片无法显示的问题?
结论:需要给图片附件设置匹配的 Content-ID
原代码在 HTML 中写了 cid:Bulldozer,但没有显式将图片附件的 Content-ID 设置为 Bulldozer。最直接的修改是保存 Attachments.Add 返回的附件对象,通过它的 PropertyAccessor.SetProperty 设置 PR_ATTACH_CONTENT_ID,使属性值与 HTML 中 cid: 后面的内容一致。
仅凭这段代码,还无法判断邮件传输过程中是否有其他因素影响图片显示。
为什么传入 ImageName 仍然无法显示?
这一行的第四个参数是 DisplayName:
.Attachments.Add imagePath, 1, 1, ImageName
DisplayName 不负责设置 Content-ID。第三个参数 Position 用于指定 Rich Text 邮件中的附件位置,也不能建立 HTML 图片与附件的 CID 关联。这些参数的用途见 Attachments.Add 官方文档。
HTML 中的引用:
<img src='cid:Bulldozer' width='400' height='300'>
需要匹配附件上的内容标识符。对应的 MAPI 属性是 PidTagAttachContentId,也称 PR_ATTACH_CONTENT_ID。其属性 ID 为 0x3712,Unicode 字符串类型为 0x001F,因此这里使用 0x3712001F。该属性与正文中 cid: 引用的关系见 Microsoft 属性说明。
修改后的 VBA 示例
以下示例沿用原来的图片路径和 Bulldozer 标识符。运行环境需要能够通过 CreateObject("Outlook.Application") 创建 Outlook 对象;发送前请填写收件人地址。
Option Explicit
Sub SendGreatEmail()
Const olMailItem As Long = 0
Const olByValue As Long = 1
Const olFormatHTML As Long = 2
Const PR_ATTACH_CONTENT_ID As String = _
"http://schemas.microsoft.com/mapi/proptag/0x3712001F"
Dim OutlookApp As Object
Dim MailItem As Object
Dim ImageAttachment As Object
Dim RecipientEmail As String
Dim EmailSubject As String
Dim imagePath As String
Dim ImageName As String
Dim EmailBody As String
RecipientEmail = "" ' Fill in the recipient before sending.
EmailSubject = "GREAT JOB TODAY! Queue Answer Rate Over 92%!"
imagePath = "C:\Avaya Report\Smiling Bulldozer.jpg"
ImageName = "Bulldozer"
If Len(Dir$(imagePath)) = 0 Then
MsgBox "Image file not found: " & imagePath, vbExclamation
Exit Sub
End If
EmailBody = "<html><body>" & _
"<img src='cid:" & ImageName & _
"' width='400' height='300'>" & _
"</body></html>"
Set OutlookApp = CreateObject("Outlook.Application")
Set MailItem = OutlookApp.CreateItem(olMailItem)
With MailItem
.BodyFormat = olFormatHTML
.To = RecipientEmail
.Subject = EmailSubject
.HTMLBody = EmailBody
.Save
Set ImageAttachment = .Attachments.Add(imagePath, olByValue)
ImageAttachment.PropertyAccessor.SetProperty _
PR_ATTACH_CONTENT_ID, ImageName
.Save
.Display
' Replace .Display with .Send to send directly.
End With
Set ImageAttachment = Nothing
Set MailItem = Nothing
Set OutlookApp = Nothing
End Sub
保留 Attachment 对象后,在该附件上设置属性:
Set ImageAttachment = .Attachments.Add(imagePath, olByValue)
ImageAttachment.PropertyAccessor.SetProperty _
PR_ATTACH_CONTENT_ID, ImageName
属性值只填写 Bulldozer,不要写成 cid:Bulldozer;cid: 前缀属于 HTML 引用。
示例在添加附件前保存邮件,并在修改属性后再次保存。第一次保存遵循 Attachments.Add 文档对一致性的建议;第二次保存符合 PropertyAccessor.SetProperty 文档中关于显式保存的说明。运行后会产生邮件草稿。
如果修改后仍然无法显示
-
确认图片文件能正常打开。检查
C:\Avaya Report\Smiling Bulldozer.jpg是否存在、是否可读取,以及文件本身是否损坏。路径中的空格不需要额外转义。 -
核对附件的 Content-ID。可以在
.Display前加入下面的语句,在 VBA 立即窗口中查看属性值,预期应为Bulldozer:Debug.Print ImageAttachment.PropertyAccessor.GetProperty(PR_ATTACH_CONTENT_ID) -
分别检查预览和实际收件结果。如果预览正常、收件后异常,检查收到的邮件是否保留了图片附件及匹配的
Content-ID。如果能取得原始 MIME,核对 HTML 的cid:Bulldozer与图片部分的Content-ID: <Bulldozer>是否对应。 -
根据差异继续定位。若接收端缺少附件或标识符发生变化,再调查邮件网关、格式转换或客户端处理。原始材料没有提供这些证据,不能直接认定是某一环节造成的。
同事也无法看到图片,并不足以证明是 Trust Center 或注册表设置导致。先补齐代码中的 CID 关联,再比较预览与接收结果,排查范围会更明确。正确嵌入后,收件人无需访问发件人电脑上的 C:\Avaya Report\ 路径。
备注:内容仅供参考。
