1. 概述

Gmail这类Webmail应用依赖IMAP(Internet Message Application Protocol)等协议从邮件服务器检索和操作邮件。本文将手把手教你用Java通过IMAP与Gmail服务器交互,涵盖以下核心操作:

  • ✅ 读取邮件
  • ✅ 统计未读邮件
  • ✅ 在文件夹间移动邮件
  • ✅ 标记已读/删除邮件
  • ⚠️ 配置Google专用应用密码

提示:本文面向有经验的Java开发者,基础概念如Maven依赖配置将快速带过。

2. IMAP是什么?

IMAP是一种允许邮件客户端从远程服务器检索邮件的技术。与POP3(Post Office Protocol)的直接下载删除不同,IMAP有以下关键特性:

  • 🔄 保留邮件在服务器端
  • 🔄 支持多设备同步访问
  • 🔄 默认使用143端口(非加密)或993端口(SSL/TLS加密,即IMAPS)

踩坑点:Gmail的特殊文件夹(如垃圾邮件)必须使用[Gmail]/前缀,直接写"Spam"会报错!

3. 项目准备

3.1 添加Maven依赖

<dependency>
    <groupId>jakarta.mail</groupId>
    <artifactId>jakarta.mail-api</artifactId>
    <version>2.1.3</version>
</dependency>

3.2 配置Gmail应用密码

  1. 访问Google账户设置
  2. 启用两步验证(2FA)(必做!)
  3. 搜索"应用密码"生成专用密码(示例:abcd efgh ijkl mnop

⚠️ 警告:普通密码无法用于IMAP,必须使用应用专用密码!

4. 连接Gmail服务器

简单粗暴的连接代码:

static Store establishConnection() throws MessagingException {
    Properties props = System.getProperties();
    props.setProperty("mail.store.protocol", "imaps");

    Session session = Session.getDefaultInstance(props, null);

    Store store = session.getStore("imaps");
    store.connect("imap.googlemail.com", "example@gmail.com", "abcd efgh ijkl mnop");
    return store;
}

关键点:

  • 使用imaps协议(加密连接)
  • 服务器地址:imap.googlemail.com
  • 认证信息:邮箱 + 应用专用密码

5. 核心操作

5.1 统计邮件数量

static void emailCount(Store store) throws MessagingException {
    Folder inbox = store.getFolder("inbox");
    Folder spam = store.getFolder("[Gmail]/Spam"); // 注意特殊前缀
    inbox.open(Folder.READ_ONLY);
    LOGGER.info("收件箱总数: " + inbox.getMessageCount());
    LOGGER.info("收件箱未读数: " + inbox.getUnreadMessageCount());
    LOGGER.info("垃圾邮件总数: " + spam.getMessageCount());
    inbox.close(true);
}

✅ 支持的Gmail特殊文件夹:

  • [Gmail]/All Mail
  • [Gmail]/Bin
  • [Gmail]/Draft
  • [Gmail]/Spam

5.2 读取邮件

static void readEmails(Store store) throws MessagingException, IOException {
    Folder inbox = store.getFolder("inbox");
    inbox.open(Folder.READ_ONLY);
    Message[] messages = inbox.getMessages();
    if (messages.length > 0) {
        Message message = messages[0];
        LOGGER.info("主题: " + message.getSubject());
        LOGGER.info("发件人: " + Arrays.toString(message.getFrom()));
        LOGGER.info("内容: " + message.getContent());
    }
    inbox.close(true);
}

5.3 搜索邮件

static void searchEmails(Store store, String from) throws MessagingException {
    Folder inbox = store.getFolder("inbox");
    inbox.open(Folder.READ_ONLY);
    SearchTerm senderTerm = new FromStringTerm(from);
    Message[] messages = inbox.search(senderTerm);
    Message[] getFirstFiveEmails = Arrays.copyOfRange(messages, 0, 5);
    for (Message message : getFirstFiveEmails) {
        LOGGER.info("主题: " + message.getSubject());
        LOGGER.info("发件人: " + Arrays.toString(message.getFrom()));
    }
    inbox.close(true);
}

💡 搜索范围仅限当前打开的文件夹

5.4 移动邮件

static void moveToFolder(Store store, Message message, String folderName) throws MessagingException {
    Folder destinationFolder = store.getFolder(folderName);
    if (!destinationFolder.exists()) {
        destinationFolder.create(Folder.HOLDS_MESSAGES); // 自动创建不存在的文件夹
    }
    Message[] messagesToMove = new Message[] { message };
    message.getFolder().copyMessages(messagesToMove, destinationFolder);
    message.setFlag(Flags.Flag.DELETED, true); // 从原文件夹删除
}

5.5 标记已读

static void markLatestUnreadAsRead(Store store) throws MessagingException {
    Folder inbox = store.getFolder("inbox");
    inbox.open(Folder.READ_WRITE); // 必须用读写模式!

    Message[] messages = inbox.search(new FlagTerm(new Flags(Flags.Flag.SEEN), false));
    if (messages.length > 0) {
        Message latestUnreadMessage = messages[messages.length - 1];
        latestUnreadMessage.setFlag(Flags.Flag.SEEN, true);
    }
    inbox.close(true);
}

⚠️ 坑:标记已读必须用Folder.READ_WRITE模式,否则会抛出异常!

5.6 删除邮件

static void deleteEmail(Store store) throws MessagingException {
    Folder inbox = store.getFolder("inbox");
    inbox.open(Folder.READ_WRITE);
    Message[] messages = inbox.getMessages();

    if (messages.length >= 7) {
        Message seventhLatestMessage = messages[messages.length - 7];
        seventhLatestMessage.setFlag(Flags.Flag.DELETED, true);
        LOGGER.info("已删除第7封邮件: " + seventhLatestMessage.getSubject());
    } else {
        LOGGER.info("收件箱不足7封邮件");
    }
    inbox.close(true);
}

💡 删除操作本质是设置DELETED标志,关闭文件夹时生效

6. 总结

本文完整演示了通过Java IMAP操作Gmail的核心流程,关键要点:

  1. 🔐 必须使用应用专用密码(非普通密码)
  2. 📁 Gmail特殊文件夹需加[Gmail]/前缀
  3. ✍️ 修改操作(标记/删除)需用READ_WRITE模式
  4. 🔄 移动邮件 = 复制 + 原地删除

完整源码见GitHub仓库,欢迎clone实践!


原始标题:Accessing Emails From Gmail Using IMAP | Baeldung