62

我正在使用 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);    
}

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

4

10 回答 10

96

这个答案扩展了 yurin 的答案。他提出的问题是 a 的内容MimeMultipart本身可能是 another 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;
}
于 2016-01-09T04:19:20.233 回答
25

这个答案扩展了Austin 的答案multipart/alternative,以通过( // without break same text appears twice in my tests)的处理来纠正原始问题。

文本出现两次,因为对于multipart/alternative,用户代理应该只选择一个部分。

来自RFC2046

“multipart/alternative”类型在语法上与“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;
}

请注意,这是一个非常简单的示例。它遗漏了许多情况,不应以当前格式在生产中使用。

于 2016-04-29T07:25:02.527 回答
22

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

科特林示例:

fun readHtmlContent(message: MimeMessage) = 
        MimeMessageParser(message).parse().htmlContent

如果电子邮件没有 html 内容,但它有纯内容(您可以通过hasPlainContenthasHtmlContent方法检查),那么您应该使用以下代码:

fun readPlainContent(message: MimeMessage) = 
        MimeMessageParser(message).parse().plainContent

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();
}
于 2019-03-24T21:50:20.773 回答
13

下面是从消息中获取文本的方法,以防 bodyParts 是文本和 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 "";
}

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

于 2015-08-07T12:35:26.373 回答
10

我不这么认为,否则如果 aPart的 mime 类型是会发生什么image/jpeg?该 API 返回一个,Object因为它在内部会尝试为您提供一些有用的东西,前提是您知道预期会是什么。对于通用软件,它打算像这样使用:

if (part.isMimeType("text/plain")) {
   ...
} else if (part.isMimeType("multipart/*")) {
   ...
} else if (part.isMimeType("message/rfc822")) {
   ...
} else {
   ...
}

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

于 2012-06-28T08:19:01.320 回答
4

如果您想始终获取文本,则可以跳过其他类型,例如“多部分”等...

  Object body = message.getContent(); 
    if(body instanceof String){
    // hey it's a text
    }
于 2012-06-28T09:07:45.727 回答
2

在我的情况下,我希望 HTML 也存在,并且我还搜索了一些已经制作的实用程序,所以我使用以下代码修复了我的

import javax.mail.Message;
import org.apache.commons.io.IOUtils;
import javax.mail.internet.MimeUtility;
.....
String body = IOUtils.toString(
                 MimeUtility.decode(message.getInputStream(), "quoted-printable"),
                 "UTF-8"
              );
于 2020-08-05T18:13:45.607 回答
0

我的答案是Austin Answer的扩展版本,但在第一种方法中有一个条件( getTextFromMessage() )。

更改:我们还应该检查 MimeType 是否为“text/html”。

检查以 '// '**结尾的行

private String getTextFromMessage(Message message) throws MessagingException, IOException {
    String result = "";
    if (message.isMimeType("text/plain")) {
        result = message.getContent().toString();
    } 

    else if (message.isMimeType("text/html")) { // **
        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;
}
于 2019-09-30T12:03:31.420 回答
0

你可以使用org.apache.commons.mail.util.MimeMessageParser

爪哇:

String htmlContent = new MimeMessageParser(message).parse().getHtmlContent();

科特林:

val htmlContent: String = MimeMessageParser(message).parse().htmlContent
于 2020-02-20T16:03:42.107 回答
0

这是我的代码,我在我的 IMAP android 应用程序中使用。它的工作。

GetTextFromMessage 返回纯文本或 html 字符串

科特林

    @Throws(IOException::class, MessagingException::class)
    private fun getTextFromMessage(message: Message): String {
        var result: String = ""
        if (message.isMimeType("text/plain")) {
            result = message.content.toString()
        }
        else if (message.isMimeType("multipart/*")) {
            val mimeMultipart =
                message.content as MimeMultipart
            result = getTextFromMimeMultipart(mimeMultipart)
        }
        else if(message.isMimeType("text/html")){
            result = message.content.toString()
        }
        return result
    }

    @Throws(IOException::class, MessagingException::class)
    private fun getTextFromMimeMultipart(
        mimeMultipart: MimeMultipart
    ): String {
        val count = mimeMultipart.count
        if (count == 0) throw MessagingException("Multipart with no body parts not supported.")

        val multipartRelated = ContentType(mimeMultipart.contentType).match("multipart/related")


        if(multipartRelated){
            val part = mimeMultipart.getBodyPart(0)
            val multipartAlt = ContentType(part.contentType).match("multipart/alternative")
            if(multipartAlt) {
                return getTextFromMimeMultipart(part.content as MimeMultipart)
            }
        }else{
            val multipartAlt = ContentType(mimeMultipart.contentType).match("multipart/alternative")
            if (multipartAlt) {
                for (i in 0 until count) {
                    val part = mimeMultipart.getBodyPart(i)
                    if (part.isMimeType("text/html")) {
                        return getTextFromBodyPart(part)
                    }
                }
            }
        }


        var result: String = ""
        for (i in 0 until count) {
            val bodyPart = mimeMultipart.getBodyPart(i)
            result += getTextFromBodyPart(bodyPart)
        }
        return result
    }

    @Throws(IOException::class, MessagingException::class)
    private fun getTextFromBodyPart(
        bodyPart: BodyPart
    ): String {
        var result: String = ""
        if (bodyPart.isMimeType("text/plain")) {
            result = bodyPart.content as String
        } else if (bodyPart.isMimeType("text/html")) {
            val html = bodyPart.content as String
            result = html
        } else if (bodyPart.content is MimeMultipart) {
            result =
                getTextFromMimeMultipart(bodyPart.content as MimeMultipart)
        }
        return result
    }
于 2020-12-01T20:55:38.697 回答