100 votes

Télécharger des pièces jointes à l'aide de Java Mail

Maintenant que j'ai téléchargé tous les messages, et que je les ai stockés dans

Message[] temp;

Comment obtenir la liste des pièces jointes pour chacun de ces messages ?

List<File> attachments;

Nota: pas de librairies tierces, s'il vous plaît, juste JavaMail.

115voto

David Rabinowitz Points 14133

Sans traitement des exceptions, mais voilà :

List<File> attachments = new ArrayList<File>();
for (Message message : temp) {
    Multipart multipart = (Multipart) message.getContent();

    for (int i = 0; i < multipart.getCount(); i++) {
        BodyPart bodyPart = multipart.getBodyPart(i);
        if(!Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition()) &&
               StringUtils.isBlank(bodyPart.getFileName())) {
            continue; // dealing with attachments only
        } 
        InputStream is = bodyPart.getInputStream();
        // -- EDIT -- SECURITY ISSUE --
        // do not do this in production code -- a malicious email can easily contain this filename: "../etc/passwd", or any other path: They can overwrite _ANY_ file on the system that this code has write access to!
//      File f = new File("/tmp/" + bodyPart.getFileName());
        FileOutputStream fos = new FileOutputStream(f);
        byte[] buf = new byte[4096];
        int bytesRead;
        while((bytesRead = is.read(buf))!=-1) {
            fos.write(buf, 0, bytesRead);
        }
        fos.close();
        attachments.add(f);
    }
}

2 votes

Mais attendez une minute, ne sommes-nous pas censés vérifier si (bodyPart.getDisposition() == Part.ATTACHMENT){} avant de sauvegarder le fichier, afin de ne pas sauvegarder le corps du courriel ?

8 votes

La lecture de StringUtils.isBlank() ne serait-elle pas plus naturelle que celle de !StringUtils.isNotBlank ?

0 votes

Cette réponse ne prend pas en compte les pièces jointes multiparties imbriquées (couramment utilisées par Thunderbird par exemple). Pour pouvoir trouver les pièces jointes multipartites imbriquées, voir la réponse de @mefi.

34voto

mefi Points 75

Cette question est très ancienne, mais elle pourra peut-être aider quelqu'un. J'aimerais développer la réponse de David Rabinowitz.

if(!Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition()))

ne devrait pas retourner toutes les pièces jointes comme vous l'attendez, parce que vous pouvez avoir du courrier où la partie mixte est sans disposition définie.

   ----boundary_328630_1e15ac03-e817-4763-af99-d4b23cfdb600
Content-Type: application/octet-stream;
    name="00000000009661222736_236225959_20130731-7.txt"
Content-Transfer-Encoding: base64

donc dans ce cas, vous pouvez aussi vérifier le nom du fichier. Comme ceci :

if (!Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition()) && StringUtils.isBlank(part.getFileName())) {...}

EDITAR

il y a un code complet qui fonctionne en utilisant la condition décrite ci-dessus Comme chaque partie peut encapsuler une autre partie et que l'attachement doit être imbriqué, la récursion est utilisée pour parcourir toutes les parties.

public List<InputStream> getAttachments(Message message) throws Exception {
    Object content = message.getContent();
    if (content instanceof String)
        return null;        

    if (content instanceof Multipart) {
        Multipart multipart = (Multipart) content;
        List<InputStream> result = new ArrayList<InputStream>();

        for (int i = 0; i < multipart.getCount(); i++) {
            result.addAll(getAttachments(multipart.getBodyPart(i)));
        }
        return result;

    }
    return null;
}

private List<InputStream> getAttachments(BodyPart part) throws Exception {
    List<InputStream> result = new ArrayList<InputStream>();
    Object content = part.getContent();
    if (content instanceof InputStream || content instanceof String) {
        if (Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition()) || StringUtils.isNotBlank(part.getFileName())) {
            result.add(part.getInputStream());
            return result;
        } else {
            return new ArrayList<InputStream>();
        }
    }

    if (content instanceof Multipart) {
            Multipart multipart = (Multipart) content;
            for (int i = 0; i < multipart.getCount(); i++) {
                BodyPart bodyPart = multipart.getBodyPart(i);
                result.addAll(getAttachments(bodyPart));
            }
    }
    return result;
}

0 votes

L'expression vérifie si le nom de fichier est vide ou null . Est-ce exact ?

0 votes

Octopus : Oui. Vérifie si une CharSequence n'est pas vide (""), pas nulle et pas uniquement composée d'espaces.

0 votes

Pouvez-vous nous dire comment convertir une liste d'entrées (List<InputStream>) en une liste de fichiers (List<File>) ?

10voto

kommradHomer Points 1601

Un gain de temps pour le code où vous enregistrez le fichier joint :

avec la version de javax mail 1.4 et après, vous pouvez dire

// SECURITY LEAK - do not do this! Do not trust the 'getFileName' input. Imagine it is: "../etc/passwd", for example.
// bodyPart.saveFile("/tmp/" + bodyPart.getFileName());

au lieu de

    InputStream is = bodyPart.getInputStream();
    File f = new File("/tmp/" + bodyPart.getFileName());
    FileOutputStream fos = new FileOutputStream(f);
    byte[] buf = new byte[4096];
    int bytesRead;
    while((bytesRead = is.read(buf))!=-1) {
        fos.write(buf, 0, bytesRead);
    }
    fos.close();

4 votes

Apparemment bodyPart doit d'abord être converti en MimeBodyPart ou autre : ((MimeBodyPart) bodyPart).saveFile("/tmp/" + bodyPart.getFileName());

6voto

Stackee007 Points 518

Vous pouvez simplement utiliser l'API Apache Commons Mail [MimeMessageParser - getAttachmentList()](http://commons.apache.org/proper/commons-email/javadocs/api-release/org/apache/commons/mail/util/MimeMessageParser.html#getAttachmentList()) ainsi que Commons IO et Commons Lang.

MimeMessageParser parser = ....
parser.parse();
for(DataSource dataSource : parser.getAttachmentList()) {

    if (StringUtils.isNotBlank(dataSource.getName())) {}

        //use apache commons IOUtils to save attachments
        IOUtils.copy(dataSource.getInputStream(), ..dataSource.getName()...)
    } else {
        //handle how you would want attachments without file names
        //ex. mails within emails have no file name
    }
}

0voto

andermirik Points 46

Renvoie la liste des parties du corps avec les pièces jointes.

@Throws(Exception::class)
    fun getAttachments(message: Message): List<BodyPart>{
        val content = message.content
        if (content is String) return ArrayList<BodyPart>()
        if (content is Multipart) {
            val result: MutableList<BodyPart> = ArrayList<BodyPart>()
            for (i in 0 until content.count) {
                result.addAll(getAttachments(content.getBodyPart(i)))
            }
            return result
        }
        return ArrayList<BodyPart>()
    }

    @Throws(Exception::class)
    private fun getAttachments(part: BodyPart): List<BodyPart> {
        val result: MutableList<BodyPart> = ArrayList<BodyPart>()

        if (Part.ATTACHMENT == part.disposition && !part.fileName.isNullOrBlank()){
            result.add(part)
        }

        val content = part.content
        if (content is Multipart) {
            for (i in 0 until (content ).count) {
                val bodyPart = content.getBodyPart(i)
                result.addAll(getAttachments(bodyPart)!!)
            }
        }
        return result
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X