Tải xuống tệp đính kèm bằng Java Mail


96

Bây giờ tôi đã tải xuống tất cả các tin nhắn và lưu trữ chúng vào

Message[] temp;

Làm cách nào để lấy danh sách các tệp đính kèm cho từng thư đó tới

List<File> attachments;

Lưu ý: vui lòng không có lib của bên thứ ba, chỉ cần JavaMail.

Câu trả lời:


109

Không có xử lý ngoại lệ, nhưng đây là:

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
Nhưng đợi một chút, chúng ta không nên kiểm tra xem (bodyPart.getDisposition () == Part.ATTACHMENT) {} trước khi lưu tệp, để nó không lưu nội dung email hay không?
folone

8
StringUtils.isBlank () sẽ dễ đọc hơn là sử dụng! StringUtils.isNotBlank phải không?
Kuchi

Câu trả lời này không xem xét các tệp đính kèm nhiều phần lồng nhau (ví dụ như thường được sử dụng bởi Thunderbird). Để có thể tìm các tệp đính kèm nhiều phần lồng nhau, hãy xem câu trả lời @mefi.
Ruslan Stelmachenko

3
Đoạn mã là một vi phạm bảo mật đang chờ xảy ra. Tôi đã chỉnh sửa đoạn mã để làm nổi bật điều này.
rzwitserloot

1
Tất nhiên, và cảm ơn vì điều đó. Đoạn mã này chỉ để chứng minh nó có thể được thực hiện như thế nào, tự nhiên nó không phải là mã sản xuất
David Rabinowitz

33

Câu hỏi rất cũ, nhưng có lẽ nó sẽ giúp ích cho ai đó. Tôi muốn mở rộng câu trả lời của David Rabinowitz.

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

không nên trả lại tất cả các bộ phận như bạn mong đợi, bởi vì bạn có thể có thư trong đó phần hỗn hợp không có sự sắp xếp xác định.

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

vì vậy trong trường hợp này, bạn cũng có thể kiểm tra tên tệp. Như thế này:

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

BIÊN TẬP

có toàn bộ mã làm việc bằng cách sử dụng điều kiện được mô tả ở trên .. Bởi vì mỗi phần có thể đóng gói các phần khác và phần đính kèm nên được lồng vào, đệ quy được sử dụng để xem qua tất cả các phần

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

biểu thức kiểm tra tên tệp trống hoặc null. Đúng không?
Keerthivasan

Bạch tuộc: Vâng. Kiểm tra xem CharSequence không trống (""), không rỗng và không chỉ khoảng trắng.
mefi

Này, bạn có thể cho biết cách chuyển đổi Danh sách <InputStream> thành Danh sách <Tập tin> không?
kumuda

kumunda: xin chào, bạn nên lặp lại danh sách đó và sử dụng org.apache.commons.io.FileUtils.copyInputStreamToFile (Nguồn InputStream, Đích tệp) và mỗi tệp thêm tệp vào một bộ sưu tập khác. Nếu bạn sử dụng ổi, kiểm tra Lists.transform (...), mà bạn có thể sử dụng instad lặp lại (phụ thuộc vào cách bạn cần phải khởi tạo mỗi trường hợp File)
mefi

9

Trình tiết kiệm thời gian cho mã nơi bạn lưu tệp đính kèm:

với javax mail phiên bản 1.4 trở lên , bạn có thể nói

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

thay vì

    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
Rõ ràng bodyPart trước tiên nên được chuyển đổi thành MimeBodyPart, chẳng hạn như:((MimeBodyPart) bodyPart).saveFile("/tmp/" + bodyPart.getFileName());
yair

5

Bạn chỉ cần sử dụng Apache Commons Mail API MimeMessageParser - getAttachmentList () cùng với Commons IO và 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
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.