web-dev-qa-db-fra.com

Comment lire le texte dans le corps du courrier à l'aide de javax.mail

je développe un courrier client à l'aide de javax.mail pour lire le courrier dans la boîte aux lettres:

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

Je sais que la méthode getContent() renvoie un objet car le contenu pourrait être un String, un MimeMultiPart, un SharedByteArrayInputstream et autres (je pense). .. Existe-t-il un moyen d'obtenir toujours le texte dans le corps du message? Merci!!

38
JackTurky

Cette réponse étend la réponse de yurin . Le problème qu'il a soulevé est que le contenu d'un MimeMultipart peut lui-même être un autre MimeMultipart. La méthode getTextFromMimeMultipart() ci-dessous se reproduit dans de tels cas sur le contenu jusqu'à ce que le corps du message ait été entièrement analysé.

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;
}
58
Austin D

Cette réponse étend la réponse d'Austin pour corriger le problème d'origine avec le traitement de multipart/alternative (// without break same text appears twice in my tests).

Le texte apparaît deux fois car pour multipart/alternative, l'agent utilisateur ne doit choisir qu'une seule partie .

De RFC2046 :

Le type "multipart/alternative" est syntaxiquement identique à "multipart/mixed", mais la sémantique est différente. En particulier, chacune des parties du corps est une version "alternative" des mêmes informations.

Les systèmes doivent reconnaître que le contenu des différentes parties est interchangeable. Les systèmes doivent choisir le "meilleur" type en fonction de l'environnement local et des références, dans certains cas, même par l'interaction de l'utilisateur. Comme pour "multipart/mixed", l'ordre des parties du corps est important. Dans ce cas, les alternatives apparaissent dans un ordre de fidélité croissante au contenu original. En général, le meilleur choix est la dernière partie d'un type pris en charge par l'environnement local du système destinataire.

Même exemple avec traitement pour les alternatives:

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

Notez qu'il s'agit d'un exemple très simple. Il manque de nombreux cas et ne doit pas être utilisé en production dans son format actuel.

19
hendalst

Ci-dessous, la méthode qui prendra le texte du message au cas où les parties du corps sont du texte et du 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 "";
}

Mise à jour. Il y a un cas, que bodyPart lui-même peut être de type multipart. (J'ai rencontré un tel e-mail après avoir écrit cette réponse.) Dans ce cas, vous devrez réécrire la méthode ci-dessus avec récursivité.

10
yurin

Je ne pense pas, sinon que se passerait-il si le type mime d'un Part était image/jpeg? L'API renvoie un Object car en interne, il essaie de vous donner quelque chose d'utile, à condition que vous sachiez ce que l'on attend. Pour les logiciels à usage général, il est destiné à être utilisé comme ceci:

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

Vous avez également le raw (en fait pas si raw , voir le Javadoc) Part.getInputStream() , mais je pense qu'il n'est pas sûr de supposer que chaque message que vous recevez est un message texte - à moins que vous n'écriviez une application très spécifique et que vous ayez le contrôle sur la source d'entrée.

9
Raffaele

Si vous voulez toujours obtenir du texte, vous pouvez ignorer d'autres types comme "multipart", etc.

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

Ne réinventez pas la roue! Vous pouvez simplement utiliser Apache Commons Email (voir ici )

Exemple de Kotlin:

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

Si le courrier électronique n'a pas de contenu html, mais qu'il a un contenu simple (vous pouvez le vérifier par les méthodes hasPlainContent et hasHtmlContent ), vous devez utiliser ce code:

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

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