Scarica gli allegati utilizzando Java Mail


96

Ora che ho scaricato tutti i messaggi e li ho archiviati in

Message[] temp;

Come ottengo l'elenco degli allegati per ciascuno di questi messaggi a

List<File> attachments;

Nota: nessuna libreria di terze parti, per favore, solo JavaMail.

Risposte:


110

Senza gestione delle eccezioni, ma qui va:

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
Ma aspetta un minuto, non dovremmo controllare se (bodyPart.getDisposition () == Part.ATTACHMENT) {} prima di salvare il file, in modo che non salvi il corpo dell'e-mail?
folone

8
StringUtils.isBlank () non sarebbe più naturale da leggere rispetto all'uso di! StringUtils.isNotBlank?
Kuchi

Questa risposta non considera gli allegati multiparte nidificati (comunemente usati da Thunderbird, ad esempio). Per poter trovare allegati multiparte nidificati, vedere la risposta @mefi.
Ruslan Stelmachenko

3
Lo snippet è una violazione della sicurezza in attesa di verificarsi. Ho modificato lo snippet per evidenziarlo.
rzwitserloot

1
Certamente, e grazie per questo. Questo frammento era solo per dimostrare come può essere fatto, naturalmente non è un codice di produzione
David Rabinowitz

33

La domanda è molto vecchia, ma forse aiuterà qualcuno. Vorrei espandere la risposta di David Rabinowitz.

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

non dovrebbe restituire tutti gli allegati come previsto, perché è possibile avere posta in cui la parte mista è priva di disposizioni definite.

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

quindi in questo caso, puoi anche controllare il nome del file. Come questo:

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

MODIFICARE

c'è un intero codice funzionante che utilizza la condizione descritta sopra .. Poiché ogni parte può incapsulare altre parti e l'attaccamento deve essere annidato, la ricorsione viene utilizzata per attraversare tutte le parti

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

l'espressione controlla il nome del file vuoto o null. È corretto?
Keerthivasan

Polpo: Sì. Controlla se un CharSequence non è vuoto (""), non è nullo e non è solo uno spazio bianco.
mefi

Ehi, puoi dire come convertire List <InputStream> in List <File>?
kumuda

kumunda: ciao, dovresti iterare quell'elenco e usare org.apache.commons.io.FileUtils.copyInputStreamToFile (sorgente InputStream, destinazione file) e aggiungere ogni file a un'altra raccolta. Se usi Guava, controlla Lists.transform (...), che puoi usare instad of iteration (dipende da come hai bisogno di inizializzare ciascuna istanza di File)
mefi

9

Un po 'di risparmio di tempo per il codice in cui salvi il file allegato:

con javax mail versione 1.4 e successive, puoi 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());

invece di

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

3
Apparentemente bodyPart dovrebbe essere prima convertito in MimeBodyPart, ad esempio:((MimeBodyPart) bodyPart).saveFile("/tmp/" + bodyPart.getFileName());
yair

5

Puoi semplicemente utilizzare Apache Commons Mail API MimeMessageParser - getAttachmentList () insieme a Commons IO e 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
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.