You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中读取Outlook .MSG文件原始内容的方案咨询

嘿,我刚好折腾过类似的需求,给你几个实用的方案来解决读取Outlook .MSG完整原始内容的问题:

方案1:获取整个.MSG文件的原始二进制内容(如果需要完整文件数据)

.MSG本身就是二进制格式,直接转String肯定会乱码或者丢失数据——毕竟它不是纯文本文件。你可以直接读取整个文件的字节数组来保存原始内容,要是需要可视化查看,转成十六进制字符串就好:

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class MsgRawContentReader {
    public static void main(String[] args) throws IOException {
        File msgFile = new File("你的文件路径/xxx.msg");
        byte[] rawBinaryContent = new byte[(int) msgFile.length()];
        
        // 用try-with-resources确保流自动关闭
        try (FileInputStream fis = new FileInputStream(msgFile)) {
            fis.read(rawBinaryContent);
        }
        
        // 如果要查看原始内容的十六进制形式
        String hexView = bytesToHex(rawBinaryContent);
        System.out.println(hexView);
        
        // 也可以把字节数组写入新文件,完全还原原始.MSG
        // Files.write(Paths.get("复制的原始文件.msg"), rawBinaryContent);
    }
    
    // 辅助方法:把字节数组转成十六进制字符串
    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X ", b));
        }
        return sb.toString().trim();
    }
}
方案2:用Apache POI HSMF挖掘所有MAPI属性(如果需要邮件的所有原始字段)

如果你要的不是整个文件的二进制,而是邮件内部的所有原始字段(比如POI默认API没暴露的那些),可以用HSMF的底层API来获取所有MAPI属性,包括自定义字段:

import org.apache.poi.hsmf.MAPIMessage;
import org.apache.poi.hsmf.datatypes.MAPIProperty;
import org.apache.poi.hsmf.datatypes.PropertyValue;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Map;

public class FullMsgPropertiesReader {
    public static void main(String[] args) throws IOException {
        try (FileInputStream fis = new FileInputStream("你的文件路径/xxx.msg");
             POIFSFileSystem poifs = new POIFSFileSystem(fis)) {
            
            MAPIMessage msg = new MAPIMessage(poifs);
            
            // 获取所有标准MAPI属性,包括POI高层API没单独封装的
            Map<MAPIProperty, PropertyValue> allStandardProps = msg.getAllProperties();
            System.out.println("=== 所有标准MAPI属性 ===");
            for (Map.Entry<MAPIProperty, PropertyValue> entry : allStandardProps.entrySet()) {
                MAPIProperty prop = entry.getKey();
                PropertyValue value = entry.getValue();
                System.out.printf("属性名: %s | ID: 0x%04X | 类型: %s | 值: %s%n",
                        prop.getName(), prop.getId(), prop.getType(), value.getValue());
            }
            
            // 获取用户自定义的属性
            Map<MAPIProperty, PropertyValue> customProps = msg.getCustomProperties();
            if (!customProps.isEmpty()) {
                System.out.println("\n=== 自定义属性 ===");
                for (Map.Entry<MAPIProperty, PropertyValue> entry : customProps.entrySet()) {
                    MAPIProperty prop = entry.getKey();
                    PropertyValue value = entry.getValue();
                    System.out.printf("自定义属性ID: 0x%04X | 类型: %s | 值: %s%n",
                            prop.getId(), prop.getType(), value.getValue());
                }
            }
        }
    }
}
方案3:直接操作OLE2复合文档读取所有流(极端情况兜底)

.MSG本质是OLE2复合文档,里面包含多个嵌套的流和目录。如果POI的HSMF还是覆盖不到你需要的内容,可以直接遍历所有OLE流,拿到最底层的原始数据:

import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class AllOleStreamsReader {
    public static void main(String[] args) throws IOException {
        try (FileInputStream fis = new FileInputStream("你的文件路径/xxx.msg");
             POIFSFileSystem poifs = new POIFSFileSystem(fis)) {
            
            DirectoryEntry rootDir = poifs.getRoot();
            // 递归遍历所有OLE目录和流
            traverseOleStructure(rootDir, "");
        }
    }
    
    private static void traverseOleStructure(DirectoryEntry dir, String currentPath) throws IOException {
        for (org.apache.poi.poifs.filesystem.Entry entry : dir) {
            String fullPath = currentPath + "/" + entry.getName();
            if (entry.isDirectoryEntry()) {
                // 如果是目录,递归进去
                traverseOleStructure((DirectoryEntry) entry, fullPath);
            } else {
                // 如果是文档流,读取原始内容
                DocumentEntry docEntry = (DocumentEntry) entry;
                System.out.printf("读取OLE流: %s | 大小: %d 字节%n", fullPath, docEntry.getSize());
                
                try (InputStream stream = docEntry.getInputStream()) {
                    byte[] streamRawContent = stream.readAllBytes();
                    // 这里可以对streamRawContent做任何你需要的处理,比如分析二进制结构
                }
            }
        }
    }
}
额外注意事项
  • 绝对不要把.MSG的二进制内容直接转成String——二进制里包含大量非文本字节,转字符串会损坏数据,一定要用字节数组或者十六进制字符串处理。
  • 如果需要深入解析.MSG的结构,可以参考微软官方的MS-OXMSG文档,里面详细定义了.MSG的OLE结构和MAPI属性规范。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 20:42:50