You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

新Outlook Web加载项:如何将选中邮件以文件附件形式转发至指定邮箱

问题

开发新Outlook Web加载项时,需要将当前选中邮件(含所有附件)发送至指定邮箱。使用Yeoman Office生成器创建项目,通过Office.context.mailbox.displayNewMessageForm实现邮件发送,但附件处理遇到问题:

  • 附件类型设为file时无法正常加载附件
  • 附件类型设为item时,附件显示为Outlook项目,打开方式与原Outlook项目一致

用户代码如下:

const subject = 'Test Subject';
const item = Office.context.mailbox.item;
console.log(item);
const itemId = Office.context.mailbox.item.itemId;

// Separate inline and regular attachments
const inlineAttachments = attachments.filter(attachment => attachment.isInline);
const regularAttachments = attachments.filter(attachment => !attachment.isInline);

// Convert the attachment IDs to REST IDs
const inlineRestIds = inlineAttachments.map(attachment => 
    Office.context.mailbox.convertToRestId(attachment.id, Office.MailboxEnums.RestVersion.v2_0)
);
const regularRestIds = regularAttachments.map(attachment => 
    Office.context.mailbox.convertToRestId(attachment.id, Office.MailboxEnums.RestVersion.v2_0)
);

// Get the email subject and body
const originalSubject = item.subject;
item.body.getAsync("html", (bodyResult) => {
    if (bodyResult.status === Office.AsyncResultStatus.Succeeded) {
        const originalBody = bodyResult.value;
        const emailHtmlBody = `
            <p><strong>Original Subject:</strong> ${originalSubject}</p>
            <p><strong>Original Body:</strong></p>
            ${originalBody}
        `;

        // Open a pre-filled compose window
        Office.context.mailbox.displayNewMessageForm({
            to: ["specific.email@example.com"],
            subject: subject,
            htmlBody: emailHtmlBody,
            attachments: [
                ...inlineRestIds.map((restId, index) => ({
                    type: 'file',
                    name: inlineAttachments[index].name,
                    url: restId,
                    isInline: true
                })),
                ...regularRestIds.map((restId, index) => ({
                    type: 'file',
                    name: regularAttachments[index].name,
                    url: restId
                }))
            ]
        });

    } else {
        console.error("Failed to get body:", bodyResult.error.message);
    }
});

解决方案

要实现将原邮件附件以普通文件形式添加到新邮件中,需通过Outlook REST API获取附件二进制内容并转换为Base64格式,再传递给displayNewMessageForm,具体步骤如下:

1. 获取访问令牌与附件二进制内容

首先获取REST API访问令牌,再通过API拉取附件的二进制数据并转换为Base64字符串:

// 获取REST访问令牌
Office.context.mailbox.getCallbackTokenAsync({ isRest: true }, (tokenResult) => {
    if (tokenResult.status !== Office.AsyncResultStatus.Succeeded) {
        console.error("获取令牌失败:", tokenResult.error.message);
        return;
    }
    
    const accessToken = tokenResult.value;
    const messageRestId = Office.context.mailbox.convertToRestId(itemId, Office.MailboxEnums.RestVersion.v2_0);

    // 批量处理所有附件
    const processAttachments = (attachmentsList, isInline) => {
        return Promise.all(attachmentsList.map(attachment => {
            const attachmentRestId = Office.context.mailbox.convertToRestId(attachment.id, Office.MailboxEnums.RestVersion.v2_0);
            const apiUrl = `https://outlook.office.com/api/v2.0/me/messages/${messageRestId}/attachments/${attachmentRestId}/$value`;

            return fetch(apiUrl, {
                headers: { 'Authorization': `Bearer ${accessToken}` }
            })
            .then(res => res.blob())
            .then(blob => {
                return new Promise((resolve) => {
                    const reader = new FileReader();
                    reader.onloadend = () => {
                        resolve({
                            name: attachment.name,
                            base64Content: reader.result.split(',')[1], // 提取Base64编码部分
                            isInline: isInline,
                            contentId: attachment.contentId // 保留内嵌附件的Content-ID
                        });
                    };
                    reader.readAsDataURL(blob);
                });
            });
        }));
    };

    // 同时处理内嵌和普通附件
    Promise.all([
        processAttachments(inlineAttachments, true),
        processAttachments(regularAttachments, false)
    ]).then(([processedInline, processedRegular]) => {
        // 后续调用displayNewMessageForm
        renderNewMessageForm([...processedInline, ...processedRegular]);
    }).catch(err => console.error("处理附件失败:", err));
});

2. 调用displayNewMessageForm添加Base64附件

将处理好的Base64附件传入displayNewMessageForm,注意file类型附件需使用base64Content字段:

function renderNewMessageForm(processedAttachments) {
    item.body.getAsync("html", (bodyResult) => {
        if (bodyResult.status !== Office.AsyncResultStatus.Succeeded) {
            console.error("获取邮件正文失败:", bodyResult.error.message);
            return;
        }

        const originalBody = bodyResult.value;
        const emailHtmlBody = `
            <p><strong>Original Subject:</strong> ${item.subject}</p>
            <p><strong>Original Body:</strong></p>
            ${originalBody}
        `;

        Office.context.mailbox.displayNewMessageForm({
            to: ["specific.email@example.com"],
            subject: 'Test Subject',
            htmlBody: emailHtmlBody,
            attachments: processedAttachments.map(att => ({
                type: 'file',
                name: att.name,
                base64Content: att.base64Content,
                isInline: att.isInline,
                contentId: att.contentId // 内嵌附件需要此ID关联正文图片
            }))
        });
    });
}

关键注意事项

  • 权限配置:确保加载项manifest.xml中声明ReadWriteMailbox权限,否则无法访问REST API获取附件
  • 异步处理:使用Promise.all确保所有附件处理完成后再调用displayNewMessageForm
  • 内嵌附件:必须保留原附件的contentId,否则正文中的内嵌图片无法正常显示

内容的提问来源于stack exchange,提问作者avnish maddheshiya

火山引擎 最新活动