2012-06-28 2 views
22

я занимаюсь разработкой клиента почты с помощью 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, MimeMultiPart, SharedByteArrayInputstream и другие (я думаю) ... Есть ли способ получить текст внутри тела сообщения? Благодаря!!

+0

Какой выход вы получаете ??? не можете ли вы использовать 'msg.getContentType()' для идентификации типа и обработки почты на основе типа? – iNan

+0

Мне не нужно знать, какой тип является содержимым, мне нужно знать только текст внутри него. – JackTurky

+0

Каждое письмо с другим типом MIME должно обрабатываться по-другому, чтобы получить текст. поэтому вам нужно переключиться с помощью 'getContentType' – iNan

ответ

37

Этот ответ распространяется на yurin's answer. Вопрос, который он поднял, состоял в том, что содержание 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; 
} 
+0

JFYI: В FAQ по JavaMail Orcale theu обрабатывают 'multipart/alternative' по-разному: http://www.oracle.com/technetwork/java/javamail/faq/index.html#mainbody. Не знаете, почему они это делают, поскольку я не знаком с 'multipart'. –

+0

спасибо, работал как шарм для меня! –

9

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

+1

Как я могу получить часть? – JackTurky

+2

['javax.mail.Message'] (http://javamail.kenai.com/nonav/javadocs/index.html?javax/mail/Message.html) реализует интерфейс' javax.mail.Part' – Raffaele

4

Если вы хотите, чтобы текст всегда, то вы можете пропустить другие типы, такие как «многочастного» и т.д. ...

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

в этом Кстати, я скачу правду? – JackTurky

+1

'instanceOf' просто оператор, а не метод в java, и это просто возвращает объект, а не тело сообщения – lakshman

9

Ниже метод, который будет принимает текст из сообщения в случае, если Частителах являются текстом и 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 ""; 
} 

Update. Есть случай, что сам bodyPart может быть типа multipart. (Я встретил такое письмо после того, как написал этот ответ.) В этом случае вам потребуется переписать выше метод с рекурсией.

+0

' // без прерывания того же текста дважды появляется в моих тестах - это потому, что вы не проводите различия между 'multipart/alternative' и 'многочастному/mixed'. 'multipart/alternative' означает, что части содержат одну и ту же информацию, но в разных представлениях. В этом случае ожидается, что пользовательский агент будет выбирать только один. См. [Здесь] (https://tools.ietf.org/html/rfc2046) – pwrex

+0

@hendlast Спасибо. – yurin

+0

Добро пожаловать. Ниже приведен пример того, как справиться с этим. В общем случае (для RFC) вы должны взять последний элемент, хотя в этом случае обычный текст предпочтительнее, так что петля через части тела, чтобы найти текстовую версию плана, вероятно, идеальна. – pwrex

9

Этот ответ расширяет Austin's answer исправить Orginal вопрос с лечением multipart/alternative (// without break same text appears twice in my tests).

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

От RFC2046:

«Альтернативный многочастный /» типа синтаксически идентичен «многочастный/смешанный», но семантика различна. В частности, каждая из частей тела является «альтернативной» версией той же информации.

Системы должны понимать, что содержание различных частей взаимозаменяемо. Системы должны выбирать «лучший» тип на основе локальной среды и ссылок, в некоторых случаях даже через взаимодействие с пользователем. Как и в случае «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; 
} 

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

+0

java.lang.ClassCastException: javax.mail.util.SharedByteArrayInputStream нельзя отнести к javax.mail.internet.MimeMultipart Я получаю эту ошибку – Jerry

+0

Это действительно отличный пример - лучший в настоящее время в Интернете, спасибо. – zalberico

Смежные вопросы