使用MS Graph API发送带EML附件邮件,非Outlook客户端无法预览
问题解决:MS Graph API发送EML附件跨客户端预览异常
核心原因
直接使用FileAttachment携带message/rfc822类型的EML文件时,Graph API可能会丢失MIME类型标记,导致接收端识别为application/octet-stream。而Gmail转发时会重新解析附件内容、修正MIME类型,因此转发后可正常预览。
解决方案
不要用FileAttachment,而是将本地EML文件解析为Graph的Message对象,通过ItemAttachment添加到邮件中。ItemAttachment不仅支持附加Outlook中已有的邮件,也支持附加本地解析生成的Message对象,无需提前在Outlook中存在。这种方式下Graph会正确识别附件的邮件类型,保留message/rfc822的MIME标记,确保跨客户端正常预览。
步骤1:添加JavaMail依赖(用于解析EML)
如果项目未引入JavaMail,需添加依赖(以Maven为例):
<dependency> <groupId>com.sun.mail</groupId> <artifactId>javax.mail</artifactId> <version>1.6.2</version> </dependency>
步骤2:修改代码实现EML解析与附件添加
替换原代码中的附件处理逻辑,改为解析EML为Message对象并使用ItemAttachment:
import com.azure.identity.ClientSecretCredentialBuilder; import com.microsoft.graph.models.*; import com.microsoft.graph.serviceclient.GraphServiceClient; import com.microsoft.graph.users.item.sendmail.SendMailPostRequestBody; import javax.mail.Session; import javax.mail.internet.MimeMessage; import java.io.File; import java.io.FileInputStream; import java.util.List; import java.util.Properties; public class GraphSendMail { private static final String USER = "user@domain.be"; public static void main(String[] args) { var credential = new ClientSecretCredentialBuilder() .clientId("clientId") .tenantId("tenantId") .clientSecret("clientSecret") .build(); var client = new GraphServiceClient(credential, "https://graph.microsoft.com/.default"); var sendMailRequest = new SendMailPostRequestBody(); Message message = new Message(); Recipient to = new Recipient(); to.setEmailAddress(new EmailAddress()); to.getEmailAddress().setAddress("receiver@gmail.com"); message.setToRecipients(List.of(to)); var sender = new Recipient(); sender.setEmailAddress(new EmailAddress()); sender.getEmailAddress().setAddress(USER); message.setSender(sender); message.setFrom(sender); message.setSubject("Test mail"); // 构建HTML邮件正文 ItemBody body = new ItemBody(); body.setContentType(BodyType.Html); body.setContent("<html><body><h1>Test body</h1></body></html>"); message.setBody(body); String filePath = "C:/pathtofile/attached-mail.eml"; File emlFile = new File(filePath); // 将本地EML解析为Graph的Message对象 Message attachedMessage = parseEmlToGraphMessage(emlFile); // 创建ItemAttachment关联解析后的邮件 ItemAttachment attachment = new ItemAttachment(); attachment.setName("attached-mail.eml"); attachment.setContentType("message/rfc822"); attachment.setItem(attachedMessage); message.setAttachments(List.of(attachment)); sendMailRequest.setMessage(message); client.users() .byUserId(USER) .sendMail() .post(sendMailRequest); System.out.println("Mail sent success"); } // 解析本地EML文件为Graph的Message对象 private static Message parseEmlToGraphMessage(File emlFile) { Message graphMessage = new Message(); try { Session session = Session.getDefaultInstance(new Properties()); MimeMessage mimeMessage = new MimeMessage(session, new FileInputStream(emlFile)); // 设置邮件主题 graphMessage.setSubject(mimeMessage.getSubject()); // 设置发件人 if (mimeMessage.getFrom() != null && mimeMessage.getFrom().length > 0) { Recipient sender = new Recipient(); EmailAddress senderAddr = new EmailAddress(); String fromStr = mimeMessage.getFrom()[0].toString(); senderAddr.setAddress(fromStr.split("<")[1].replace(">", "")); senderAddr.setName(fromStr.split("<")[0].trim()); sender.setEmailAddress(senderAddr); graphMessage.setSender(sender); graphMessage.setFrom(sender); } // 设置收件人(可按需扩展处理Cc/Bcc) if (mimeMessage.getRecipients(javax.mail.Message.RecipientType.TO) != null) { List<Recipient> toRecipients = List.of(mimeMessage.getRecipients(javax.mail.Message.RecipientType.TO)).stream() .map(addr -> { Recipient recipient = new Recipient(); EmailAddress emailAddr = new EmailAddress(); String addrStr = addr.toString(); emailAddr.setAddress(addrStr.split("<")[1].replace(">", "")); emailAddr.setName(addrStr.split("<")[0].trim()); recipient.setEmailAddress(emailAddr); return recipient; }).toList(); graphMessage.setToRecipients(toRecipients); } // 设置邮件正文 ItemBody body = new ItemBody(); if (mimeMessage.getContentType().contains("text/html")) { body.setContentType(BodyType.Html); body.setContent(mimeMessage.getContent().toString()); } else { body.setContentType(BodyType.Text); body.setContent(mimeMessage.getContent().toString()); } graphMessage.setBody(body); } catch (Exception e) { e.printStackTrace(); } return graphMessage; } }
关键说明
- 解析EML时通过JavaMail完整提取原邮件的主题、发件人、收件人、正文等元数据,确保附加的邮件内容完整。
ItemAttachment会被Graph标记为message/rfc822类型,Gmail等客户端可直接识别并预览,无需额外处理。
内容的提问来源于stack exchange,提问作者JoeriMJ
相关产品推荐
相关产品推荐

