Завантажуйте вкладення за допомогою Java Mail


96

Тепер, коли я завантажив усі повідомлення та зберігаю їх у

Message[] temp;

Як отримати список вкладень до кожного з цих повідомлень?

List<File> attachments;

Примітка: будь-яких третіх сторін, будь ласка, лише JavaMail.

Відповіді:


109

Без винятку обробка, але тут йдеться:

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
Але зачекайте хвилинку, хіба ми не повинні перевіряти, чи (bodyPart.getDisposition () == Part.ATTACHMENT) {} перед збереженням файлу, щоб він не зберігав тіло повідомлення електронної пошти?
фолоун

8
Чи не буде StringUtils.isBlank () більш природним для читання, ніж використання! StringUtils.isNotBlank?
Кучі

Ця відповідь не враховує вкладені багаточастинні вкладення (наприклад, зазвичай використовувані Thunderbird). Щоб знайти вкладені багаточастинні вкладення, див. Відповідь @mefi.
Руслан Стельмаченко

3
Фрагмент - це порушення безпеки, яке чекає. Я відредагував фрагмент, щоб виділити це.
rzwitserloot

1
Звичайно, і дякую за це. Цей фрагмент мав лише продемонструвати, як це можна зробити, природно, це не виробничий код
Девід Рабіновіц

33

Питання дуже давнє, але, можливо, воно комусь допоможе. Я хотів би розширити відповідь Девіда Рабіновіца.

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

не повинен повертати всі додатки, як ви очікуєте, тому що ви можете мати пошту там, де є змішана частина, без певного розпорядження.

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

так що в цьому випадку ви також можете перевірити ім'я файлу. Подобається це:

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

EDIT

є цілий робочий код з використанням умови, описаної вище .. Оскільки кожна частина може інкапсулювати інші частини, і вкладення повинно бути вкладеним, рекурсія використовується для проходження по всіх частинах

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

вираз перевіряє ім'я файлу порожнім або null. Це правильно?
Keerthivasan

Восьминіг: Так. Перевіряє, чи не є CharSequence порожнім (""), не має значення null і не є лише пробілами.
мефі

Гей, ви можете сказати, як перетворити List <InputStream> у List <File>?
kumuda

kumunda: привіт, вам слід повторити цей список і використати org.apache.commons.io.FileUtils.copyInputStreamToFile (джерело InputStream, призначення файлу) та додати кожен файл до іншої колекції. Якщо ви використовуєте Guava, перевірте Lists.transform (...), який ви можете використовувати instad ітерації (залежить від того, як вам потрібно ініціалізувати кожен екземпляр файлу)
mefi

9

Заощаджуйте час для коду, де ви зберігаєте файл вкладення:

з поштою javax версії 1.4 і пізніше, можна сказати

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

замість

    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
Очевидно, bodyPart спочатку слід перетворити на MimeBodyPartтакий, як:((MimeBodyPart) bodyPart).saveFile("/tmp/" + bodyPart.getFileName());
yair

5

Ви можете просто використовувати Apache Commons Mail API MimeMessageParser - getAttachmentList () разом із Commons IO та 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
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.