Ekleri Java Mail kullanarak indirin


96

Artık tüm mesajları indirdiğime göre

Message[] temp;

Bu mesajların her biri için eklerin listesini nasıl alırım?

List<File> attachments;

Not: üçüncü taraf kütüphaneleri kullanmayın, lütfen sadece JavaMail.

Yanıtlar:


111

İstisna olmadan, ama burada:

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
Ama bir dakika bekleyin, dosyayı kaydetmeden önce (bodyPart.getDisposition () == Part.ATTACHMENT) {} e-postanın gövdesini kaydetmemesi için kontrol etmemiz gerekmiyor mu?
folone

8
StringUtils.isBlank () 'i okumak! StringUtils.isNotBlank kullanmaktan daha doğal olmaz mıydı?
Kuchi

Bu yanıt, iç içe geçmiş çok parçalı ekleri dikkate almaz (örneğin Thunderbird tarafından yaygın olarak kullanılır). İç içe geçmiş çok parçalı ekleri bulabilmek için @mefi cevabına bakın.
Ruslan Stelmachenko

3
Snippet, gerçekleşmeyi bekleyen bir güvenlik ihlalidir. Bunu vurgulamak için pasajı düzenledim.
rzwitserloot

1
Tabii ki ve bunun için teşekkürler. Bu pasaj sadece nasıl yapılabileceğini göstermek içindi, doğal olarak bir üretim kodu değil
David Rabinowitz

33

Soru çok eski, ama belki birine yardımcı olur. David Rabinowitz'in cevabını genişletmek istiyorum.

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

tüm ataşmanları beklediğiniz gibi geri döndürmemelidir, çünkü karışık bölümün tanımlanmış bir eğilim olmadığı durumlarda postaya sahip olabilirsiniz.

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

yani bu durumda dosya adını da kontrol edebilirsiniz. Bunun gibi:

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

DÜZENLE

yukarıda açıklanan koşulu kullanan tam bir çalışma kodu vardır .. Her parça başka parçaları kapsayabildiğinden ve ekin iç içe olması gerektiğinden, tüm parçalarda gezinmek için özyineleme kullanılır

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

ifade boş veya boş dosya adını kontrol eder null. Bu doğru mu?
Keerthivasan

Ahtapot: Evet. Bir CharSequence öğesinin boş ("") olup olmadığını, null olmadığını ve yalnızca boşluk olmadığını kontrol eder.
mefi

List <InputStream> 'i List <File>' a nasıl dönüştüreceğinizi söyleyebilir misiniz?
kumuda

kumunda: merhaba, bu listeyi yinelemeli ve org.apache.commons.io.FileUtils.copyInputStreamToFile (InputStream kaynağı, Dosya hedefi) kullanmalı ve her biri başka bir koleksiyona dosya eklemelisiniz. Guava kullanıyorsanız, instad iteration kullanabileceğiniz Lists.transform (...) 'u kontrol edin (her File örneğini nasıl başlatmanız gerektiğine bağlıdır)
mefi

9

Ek dosyasını kaydettiğiniz kod için biraz zaman kazandıran:

javax posta sürümü 1.4 ve sonrasında şunu söyleyebilirsiniz:

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

onun yerine

    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
Görünüşe göre bodyPart ilk önce şu MimeBodyPart((MimeBodyPart) bodyPart).saveFile("/tmp/" + bodyPart.getFileName());
şekle

5

Apache Commons Mail API MimeMessageParser - getAttachmentList () Commons IO ve Commons Lang ile birlikte basitçe kullanabilirsiniz .

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
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.