如何使用javax.mail读取邮件正文中的文本

Jac*_*rky 42 java mime multipart javax.mail

我正在使用javax.mail开发客户端邮件来读取邮箱内的邮件:

Properties properties = System.getProperties();  
properties.setProperty("mail.store.protocol", "imap");  
try {  
    Session session = Session.getDefaultInstance(properties, null);
    Store store = session.getStore("pop3");//create store instance  
    store.connect("pop3.domain.it", "mail.it", "*****");  
    Folder inbox = store.getFolder("inbox");  
    FlagTerm ft = new FlagTerm(new Flags(Flags.Flag.SEEN), false);
    inbox.open(Folder.READ_ONLY);//set access type of Inbox  
    Message messages[] = inbox.search(ft);
    String mail,sub,bodyText="";
    Object body;
    for(Message message:messages) {
        mail = message.getFrom()[0].toString();
        sub = message.getSubject();
        body = message.getContent();
        //bodyText = body.....
    }
} catch (Exception e) {  
    System.out.println(e);    
}
Run Code Online (Sandbox Code Playgroud)

我知道该方法getContent()返回一个对象,因为内容可能是a String,a MimeMultiPart,a SharedByteArrayInputstream和其他(我认为)......有没有办法在消息正文中获取文本?谢谢!!

Aus*_*n D 66

这个答案延伸了yurin的答案.他提出的问题是,一个人的内容MimeMultipart可能本身就是另一个MimeMultipart.getTextFromMimeMultipart()下面的方法在这种情况下对内容进行递归,直到完全解析了消息体.

private String getTextFromMessage(Message message) throws MessagingException, IOException {
    String result = "";
    if (message.isMimeType("text/plain")) {
        result = message.getContent().toString();
    } else if (message.isMimeType("multipart/*")) {
        MimeMultipart mimeMultipart = (MimeMultipart) message.getContent();
        result = getTextFromMimeMultipart(mimeMultipart);
    }
    return result;
}

private String getTextFromMimeMultipart(
        MimeMultipart mimeMultipart)  throws MessagingException, IOException{
    String result = "";
    int count = mimeMultipart.getCount();
    for (int i = 0; i < count; i++) {
        BodyPart bodyPart = mimeMultipart.getBodyPart(i);
        if (bodyPart.isMimeType("text/plain")) {
            result = result + "\n" + bodyPart.getContent();
            break; // without break same text appears twice in my tests
        } else if (bodyPart.isMimeType("text/html")) {
            String html = (String) bodyPart.getContent();
            result = result + "\n" + org.jsoup.Jsoup.parse(html).text();
        } else if (bodyPart.getContent() instanceof MimeMultipart){
            result = result + getTextFromMimeMultipart((MimeMultipart)bodyPart.getContent());
        }
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)


hen*_*lst 22

这个答案扩展了奥斯汀的答案,以纠正处理multipart/alternative(// without break same text appears twice in my tests)的原始问题.

文本出现两次因为multipart/alternative,用户代理只能选择一个部分.

来自RFC2046:

"multipart/alternative"类型在语法上与"multipart/mixed"相同,但语义不同.特别地,每个身体部位是相同信息的"替代"版本.

系统应该认识到各个部分的内容是可以互换的.系统应根据本地环境和参考选择"最佳"类型,在某些情况下甚至通过用户交互.与"multipart/mixed"一样,身体部位的顺序也很重要.在这种情况下,替代方案以对原始内容的忠诚度增加的顺序出现.通常,最佳选择是接收方系统本地环境支持的类型的最后部分.

与替代品处理相同的例子:

private String getTextFromMessage(Message message) throws IOException, MessagingException {
    String result = "";
    if (message.isMimeType("text/plain")) {
        result = message.getContent().toString();
    } else if (message.isMimeType("multipart/*")) {
        MimeMultipart mimeMultipart = (MimeMultipart) message.getContent();
        result = getTextFromMimeMultipart(mimeMultipart);
    }
    return result;
}

private String getTextFromMimeMultipart(
        MimeMultipart mimeMultipart) throws IOException, MessagingException {

    int count = mimeMultipart.getCount();
    if (count == 0)
        throw new MessagingException("Multipart with no body parts not supported.");
    boolean multipartAlt = new ContentType(mimeMultipart.getContentType()).match("multipart/alternative");
    if (multipartAlt)
        // alternatives appear in an order of increasing 
        // faithfulness to the original content. Customize as req'd.
        return getTextFromBodyPart(mimeMultipart.getBodyPart(count - 1));
    String result = "";
    for (int i = 0; i < count; i++) {
        BodyPart bodyPart = mimeMultipart.getBodyPart(i);
        result += getTextFromBodyPart(bodyPart);
    }
    return result;
}

private String getTextFromBodyPart(
        BodyPart bodyPart) throws IOException, MessagingException {

    String result = "";
    if (bodyPart.isMimeType("text/plain")) {
        result = (String) bodyPart.getContent();
    } else if (bodyPart.isMimeType("text/html")) {
        String html = (String) bodyPart.getContent();
        result = org.jsoup.Jsoup.parse(html).text();
    } else if (bodyPart.getContent() instanceof MimeMultipart){
        result = getTextFromMimeMultipart((MimeMultipart)bodyPart.getContent());
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

请注意,这是一个非常简单的示例.它错过了很多案例,不应该以当前格式用于生产.

  • 这是一个非常好的例子 - 目前在互联网上最好的,谢谢. (3认同)

yur*_*rin 11

下面是在bodyParts是text和html的情况下从消息中获取文本的方法.

  import javax.mail.BodyPart;
  import javax.mail.Message;
  import javax.mail.internet.MimeMultipart;
  import org.jsoup.Jsoup;

  ....    
  private String getTextFromMessage(Message message) throws Exception {
    if (message.isMimeType("text/plain")){
        return message.getContent().toString();
    }else if (message.isMimeType("multipart/*")) {
        String result = "";
        MimeMultipart mimeMultipart = (MimeMultipart)message.getContent();
        int count = mimeMultipart.getCount();
        for (int i = 0; i < count; i ++){
            BodyPart bodyPart = mimeMultipart.getBodyPart(i);
            if (bodyPart.isMimeType("text/plain")){
                result = result + "\n" + bodyPart.getContent();
                break;  //without break same text appears twice in my tests
            } else if (bodyPart.isMimeType("text/html")){
                String html = (String) bodyPart.getContent();
                result = result + "\n" + Jsoup.parse(html).text();

            }
        }
        return result;
    }
    return "";
}
Run Code Online (Sandbox Code Playgroud)

更新.有一种情况,bodyPart本身可以是multipart类型.(在写完这个答案之后我遇到了这样的电子邮件.)在这种情况下,你需要用递归重写上面的方法.


Raf*_*ele 10

我不这么认为,否则如果一个Part哑剧类型是什么会发生什么image/jpeg?API返回一个Object因为在内部它会尝试给你一些有用的东西,前提是你知道预期的内容.对于通用软件,它的用途如下:

if (part.isMimeType("text/plain")) {
   ...
} else if (part.isMimeType("multipart/*")) {
   ...
} else if (part.isMimeType("message/rfc822")) {
   ...
} else {
   ...
}
Run Code Online (Sandbox Code Playgroud)

你也有原始的(实际上不那么原始,请参阅Javadoc)Part.getInputStream(),但我认为假设你收到的每条消息都是基于文本的消息是不安全的 - 除非你正在编写一个非常具体的应用程序并且你可以控制它输入源.

  • [`javax.mail.Message`](http://javamail.kenai.com/nonav/javadocs/index.html?javax/mail/Message.html)实现`javax.mail.Part`接口 (2认同)

gro*_*gor 6

不要重新发明轮子!您可以简单地使用Apache Commons Email(请参阅此处

Kotlin示例:

fun readHtmlContent(message: MimeMessage) = 
        MimeMessageParser(message).parse().htmlContent
Run Code Online (Sandbox Code Playgroud)

如果电子邮件不包含html内容,但是包含简单内容(可以通过hasPlainContenthasHtmlContent方法进行检查),则应使用以下代码:

fun readPlainContent(message: MimeMessage) = 
        MimeMessageParser(message).parse().plainContent
Run Code Online (Sandbox Code Playgroud)

Java示例:

String readHtmlContent(MimeMessage message) throws Exception {
    return new MimeMessageParser(message).parse().getHtmlContent();
}

String readPlainContent(MimeMessage message) throws Exception {
    return new MimeMessageParser(message).parse().getPlainContent();
}
Run Code Online (Sandbox Code Playgroud)

  • 这太棒了!java 部分完美地完成了这个任务,而且简单干净 (2认同)