Подтвердить что ты не робот

Как читать текст внутри тела почты с помощью 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);    
}

Я знаю, что метод getContent() возвращает объект, потому что контент может быть String, a MimeMultiPart, a SharedByteArrayInputstream и другие (я думаю)... Есть ли способ всегда получать текст внутри тела сообщения? Благодарю!!

4b9b3361

Ответ 1

Этот ответ расширяет ответ 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;
}

Ответ 2

Этот ответ расширяет ответ остина, чтобы исправить первоначальную проблему с лечением multipart/alternative (// without break same text appears twice in my tests).

Текст появляется дважды, потому что для multipart/alternative пользовательский агент должен выбирать только одну часть.

С RFC2046:

Тип "multipart/alternative" синтаксически идентичен типу "multipart/mixed", но семантика различна. В частности, каждая из частей тела является "альтернативной" версией той же информации.

Системы должны понимать, что содержимое различных частей взаимозаменяемо. Системы должны выбирать "лучший" тип на основе локальной среды и ссылок, в некоторых случаях даже через взаимодействие с пользователем. Как и в случае "multipart/mixed", порядок частей тела является значительным. В этом случае альтернативы появляются в порядке возрастания точности исходного контента. В общем, лучшим выбором является LAST-часть типа, поддерживаемого локальной средой системы получателя.

Тот же пример с обработкой альтернатив:

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;
}

Обратите внимание, что это очень простой пример. Он пропускает множество случаев и не должен использоваться в производстве в его нынешнем формате.

Ответ 3

Я так не думаю, иначе что произойдет, если тип mime Part - image/jpeg? API возвращает Object, потому что внутренне он пытается дать вам что-то полезное, если вы знаете, что ожидается. Для программного обеспечения общего назначения оно предназначено для использования следующим образом:

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

У вас также есть необработанный (на самом деле не такой сырой, см. Javadoc) Part.getInputStream(), но я считаю, что небезопасно предполагать, что каждый и каждое полученное сообщение является текстовым, если вы не пишете очень специфическое приложение, и у вас есть контроль над источником ввода.

Ответ 4

Ниже приведен метод, который будет принимать текст из сообщения, если 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. (Я встретил такое письмо после того, как написал этот ответ.) В этом случае вам потребуется переписать выше метод с рекурсией.

Ответ 5

Не изобретай велосипед! Вы можете просто использовать электронную почту Apache Commons (см. здесь)

Пример Kotlin:

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

Если электронное письмо не содержит html-содержимого, но содержит простое содержимое (вы можете проверить это с помощью методов hasPlainContent и hasHtmlContent), вам следует использовать этот код:

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();
}

Ответ 6

Если вы хотите всегда получать текст, вы можете пропустить другие типы, такие как "multipart" и т.д.

  Object body = message.getContent(); 
    if(body instanceof String){
    // hey it a text
    }

Ответ 7

Мой ответ - расширенная версия Ответа Остина, но с одним условием в первом методе (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;
}