Jak odczytać tekst wewnątrz wiadomości za pomocą javax.poczta

Rozwijam pocztę klienta używając javaxa.mail to read mail inside mail box:

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

Wiem, że metoda getContent() zwraca obiekt, ponieważ zawartość może być String, a MimeMultiPart, a SharedByteArrayInputstream i inne ( myślę )... Czy istnieje sposób, aby zawsze uzyskać tekst wewnątrz wiadomości? Dzięki!!

Author: JackTurky, 2012-06-28

5 answers

Ta odpowiedź rozszerzaodpowiedź Yurina . Problem, który poruszył, polegał na tym, że Treść MimeMultipart może być sama w sobie inną MimeMultipart. Poniższa metoda getTextFromMimeMultipart() rekursuje w takich przypadkach zawartość do momentu pełnego przetworzenia treści wiadomości.

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;
}
 44
Author: Austin D,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-12 09:51:17

Ta odpowiedź rozszerza odpowiedź Austina , aby naprawić oryginalny problem z traktowaniem multipart/alternative (// without break same text appears twice in my tests).

Tekst pojawia się dwa razy, ponieważ dla multipart/alternative, agent użytkownika powinien wybrać tylko jedną część.

From RFC2046 :

Typ "multipart/alternative" jest składniowo identyczny z "multipart / mixed", ale semantyka jest inna. W szczególności każda z części ciała jest "alternatywną" wersją tego samego informacje.

Systemy powinny uznawać, że zawartość poszczególnych części jest wymienna. Systemy powinny wybrać "najlepszy" typ na podstawie lokalnego środowiska i odniesień, w niektórych przypadkach nawet poprzez interakcję z użytkownikiem. Podobnie jak w przypadku "multipart / mixed", kolejność części ciała jest znacząca. W tym przypadku alternatywy pojawiają się w kolejności rosnącej wierności oryginalnej treści. Ogólnie rzecz biorąc, najlepszym wyborem jest ostatnia część typu obsługiwanego przez odbiorcę lokalne środowisko systemu.

Ten sam przykład z leczeniem alternatywnym:

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

Zauważ, że jest to bardzo prosty przykład. Pomija wiele przypadków i nie powinien być używany w produkcji w obecnym formacie.

 13
Author: pwrex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:33

Poniżej znajduje się metoda, która pobiera tekst z wiadomości w przypadku, gdy bodyParts to text i 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 . Istnieje przypadek, że część ciała może być typu multipart. (Spotkałem takiego e-maila po napisaniu tej odpowiedzi.) W tym przypadku będziesz musiał przepisać powyższą metodę z rekurencją.

 10
Author: yurin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-08 17:36:49

Nie wydaje mi się, inaczej co by się stało, gdyby typ mime Part to image/jpeg? API zwraca Object, ponieważ wewnętrznie próbuje dać ci coś użytecznego, pod warunkiem, że wiesz, czego oczekujesz. W przypadku oprogramowania ogólnego przeznaczenia jest on przeznaczony do użycia w następujący sposób:

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

Masz również raw (właściwie nie tak raw , patrz Javadoc) Part.getInputStream(), ale myślę, że nie jest bezpieczne zakładanie, że każda wiadomość, którą otrzymujesz, jest tekstowa-chyba że jesteś pisząc bardzo konkretną aplikację masz kontrolę nad źródłem danych wejściowych.

 9
Author: Raffaele,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-28 08:19:01

Jeśli chcesz uzyskać tekst zawsze możesz pominąć inne typy, takie jak 'multipart' itp...

  Object body = message.getContent(); 
    if(body instanceof String){
    // hey it's a text
    }
 4
Author: JAVAGeek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-24 05:51:30