2012-11-11 32 views
9

Tôi đã viết một ứng dụng nhận tất cả email từ một hộp thư đến, lọc các email có chứa một chuỗi cụ thể và sau đó đặt các email đó trong một ArrayList.Làm cách nào để xử lý nhiều thư/thư thay thế bằng JavaMail?

Sau khi email được đưa vào Danh sách, tôi đang thực hiện một số nội dung với chủ đề và nội dung của các email đã nêu. Điều này làm việc tốt cho e-mail mà không có phần đính kèm. Nhưng khi tôi bắt đầu sử dụng e-mail với các tập tin đính kèm, tất cả đều không hoạt động như mong đợi nữa.

Đây là mã của tôi:

public void getInhoud(Message msg) throws IOException { 
    try { 
     cont = msg.getContent(); 
    } catch (MessagingException ex) { 
     Logger.getLogger(ReadMailNew.class.getName()).log(Level.SEVERE, null, ex); 
    } 
    if (cont instanceof String) { 
     String body = (String) cont; 


    } else if (cont instanceof Multipart) { 
     try { 
      Multipart mp = (Multipart) msg.getContent(); 
      int mp_count = mp.getCount(); 
      for (int b = 0; b < 1; b++) { 
        dumpPart(mp.getBodyPart(b)); 
      } 
     } catch (Exception ex) { 
      System.out.println("Exception arise at get Content"); 
      ex.printStackTrace(); 
     } 
    } 
} 

public void dumpPart(Part p) throws Exception { 
    email = null; 
    String contentType = p.getContentType(); 
    System.out.println("dumpPart" + contentType); 
    InputStream is = p.getInputStream(); 
    if (!(is instanceof BufferedInputStream)) { 
     is = new BufferedInputStream(is); 
    } 
    int c; 
    final StringWriter sw = new StringWriter(); 
    while ((c = is.read()) != -1) { 
     sw.write(c); 
    } 

    if (!sw.toString().contains("<div>")) { 
     mpMessage = sw.toString(); 
     getReferentie(mpMessage); 
    } 
} 

Các nội dung từ các e-mail được lưu trữ trong một String.

Mã này hoạt động tốt khi tôi cố đọc thư mà không có tệp đính kèm. Nhưng nếu tôi sử dụng một e-mail với tập tin đính kèm, String cũng chứa mã HTML và thậm chí cả mã hóa tệp đính kèm. Cuối cùng tôi muốn lưu trữ tập tin đính kèm và nội dung của một e-mail, nhưng ưu tiên hàng đầu của tôi là chỉ nhận được văn bản mà không cần bất kỳ mã HTML hoặc tệp đính kèm nào.

Bây giờ tôi đã cố gắng một cách tiếp cận khác nhau để xử lý các bộ phận khác nhau:

public void getInhoud(Message msg) throws IOException { 
    try { 
     Object contt = msg.getContent(); 

     if (contt instanceof Multipart) { 
      System.out.println("Met attachment"); 
      handleMultipart((Multipart) contt); 
     } else { 
      handlePart(msg); 
      System.out.println("Zonder attachment"); 

     } 
    } catch (MessagingException ex) { 
     ex.printStackTrace(); 
    } 
} 

public static void handleMultipart(Multipart multipart) 
     throws MessagingException, IOException { 
    for (int i = 0, n = multipart.getCount(); i < n; i++) { 
     handlePart(multipart.getBodyPart(i)); 
     System.out.println("Count "+n); 
    } 
} 

public static void handlePart(Part part) 
     throws MessagingException, IOException { 

    String disposition = part.getDisposition(); 
    String contentType = part.getContentType(); 
    if (disposition == null) { // When just body 
     System.out.println("Null: " + contentType); 
     // Check if plain 
     if ((contentType.length() >= 10) 
       && (contentType.toLowerCase().substring(
       0, 10).equals("text/plain"))) { 
      part.writeTo(System.out); 
     } else if ((contentType.length() >= 9) 
       && (contentType.toLowerCase().substring(
       0, 9).equals("text/html"))) { 
      part.writeTo(System.out); 
     } else if ((contentType.length() >= 9) 
       && (contentType.toLowerCase().substring(
       0, 9).equals("text/html"))) { 
      System.out.println("Ook html gevonden"); 
      part.writeTo(System.out); 
     }else{ 
      System.out.println("Other body: " + contentType); 
      part.writeTo(System.out); 
     } 
    } else if (disposition.equalsIgnoreCase(Part.ATTACHMENT)) { 
     System.out.println("Attachment: " + part.getFileName() 
       + " : " + contentType); 
    } else if (disposition.equalsIgnoreCase(Part.INLINE)) { 
     System.out.println("Inline: " 
       + part.getFileName() 
       + " : " + contentType); 
    } else { 
     System.out.println("Other: " + disposition); 
    } 
} 

Đây là những gì được trả về từ các System.out.printlns

Null: multipart/alternative; boundary=047d7b6220720b499504ce3786d7 
Other body: multipart/alternative; boundary=047d7b6220720b499504ce3786d7 
Content-Type: multipart/alternative; boundary="047d7b6220720b499504ce3786d7" 

--047d7b6220720b499504ce3786d7 
Content-Type: text/plain; charset="ISO-8859-1" 

'Text of the message here in normal text' 

--047d7b6220720b499504ce3786d7 
Content-Type: text/html; charset="ISO-8859-1" 
Content-Transfer-Encoding: quoted-printable 

'HTML code of the message' 

Cách tiếp cận này sẽ trả về văn bản bình thường của e-mail nhưng cũng là mã HTML của thư. Tôi thực sự không hiểu tại sao điều này xảy ra, tôi đã googled nó nhưng có vẻ như không có ai khác với vấn đề này.

Bất kỳ trợ giúp nào được đánh giá cao,

Cảm ơn!

+1

Làm cách nào để tạo các trường hợp 'Tin nhắn'? Bạn có sử dụng triển khai mặc định JavaMail không, phiên bản nào? Bạn có thao túng thân thể của các thông điệp của mình bằng cách nào đó trước khi cho chúng ăn 'thói quen getInhoud' không? Tôi vừa thử mẫu mã của bạn và nó đã làm việc cho tôi (JM 1.4.5). –

+0

Gợi ý hữu ích: Nếu bạn muốn câu trả lời cụ thể cho câu hỏi của bạn, hãy thử cung cấp cho chúng tôi một SSCCE (http://sscce.org/). –

Trả lời

20

tôi thấy đọc e-mail với thư viện JavaMail nhiều khó khăn hơn so với dự kiến. Tôi không đổ lỗi cho API JavaMail, thay vào đó tôi đổ lỗi cho sự hiểu biết kém của tôi về RFC-822 - định nghĩa chính thức của Internet e-mail.

Là một thử nghiệm suy nghĩ: Hãy xem xét sự phức tạp của thư điện tử có thể trở thành thế giới thực. Có thể gửi tin nhắn nhúng "vô hạn" trong các tin nhắn. Mỗi thư có thể có nhiều tệp đính kèm (văn bản nhị phân hoặc văn bản có thể đọc được). Bây giờ hãy tưởng tượng cấu trúc này phức tạp như thế nào trong JavaMail API sau khi phân tích cú pháp.

Một vài mẹo có thể giúp khi đi qua e-mail với JavaMail:

Message, Multipart, và BodyPart tất cả thực hiện Part. Nếu có thể, hãy xử lý mọi thứ dưới dạng Part. Điều này sẽ cho phép các phương thức traversal chung được xây dựng dễ dàng hơn.

Những Part phương pháp này sẽ giúp đỡ để đi qua:

  • String getContentType(): Bắt đầu với kiểu MIME. Bạn có thể bị cám dỗ để coi đây là loại MIME (với một số hack/cắt/khớp), nhưng không. Tốt hơn là chỉ sử dụng phương pháp này bên trong trình gỡ lỗi để kiểm tra.
    • Thật kỳ lạ, không thể trích xuất loại MIME trực tiếp. Thay vào đó hãy sử dụng boolean isMimeType(String) để khớp. Đọc kỹ tài liệu để tìm hiểu về các ký tự đại diện mạnh mẽ, chẳng hạn như "multipart/*".
  • Object getContent(): Có thể instanceof:
    • Multipart - thùng chứa để biết thêm Part s
      • Cast để Multipart, sau đó lặp lại như zero-based index với int getCount()BodyPart getBodyPart(int)
        • Lưu ý: BodyPart thực hiện Part
      • Theo kinh nghiệm của tôi, máy chủ Microsoft Exchange thường xuyên cung cấp hai bản sao văn bản nội dung: văn bản thuần tuý và HTML.
        • Để phù hợp với văn bản đơn giản, hãy thử: Part.isMimeType("text/plain")
        • Để phù hợp với HTML, hãy thử: Part.isMimeType("text/html")
    • Message (dụng cụ Part) - nhúng hoặc kèm theo e-mail
    • String (chỉ văn bản nội dung - văn bản thuần túy hoặc HTML)
      • S ee lưu ý ở trên về các máy chủ Microsoft Exchange.
    • InputStream (có thể là một tập tin đính kèm Base64 mã hóa)
  • String getDisposition(): Giá trị có thể được null
    • nếu Part.ATTACHMENT.equalsIgnoreCase(getDisposition()), sau đó gọi getInputStream() để có được byte liệu của tập tin đính kèm.

Cuối cùng, tôi thấy official Javadocs loại trừ tất cả mọi thứ trong gói com.sun.mail (và có thể nhiều hơn). Nếu bạn cần, hãy đọc mã trực tiếp hoặc tạo Javadocs chưa được lọc theo downloading the source và chạy mvn javadoc:javadoc trong mô-đun dự án mail của dự án.

+0

Cảm ơn bạn đã nhập! Tại thời điểm này điều này không liên quan đến tôi nữa, nhưng tôi có thể hiểu nó có thể sẽ hữu ích cho những người khác đấu tranh với vấn đề này. – Jef

+1

'Multipart' không mở rộng giao diện' Phần'. – RRM

+0

@RRM: Bắt tốt. Đã sửa lỗi và cải tiến. – kevinarpe

1

Theo dõi lời khuyên hữu ích của Kevin, việc phân tích các loại đối tượng Java nội dung email của bạn liên quan đến tên chuẩn (hoặc tên đơn giản) cũng có thể hữu ích.Ví dụ, nhìn vào một hộp thư đến tôi đã có ngay bây giờ, trong số 486 thư là 399, và 87 là MimeMultipart. Điều này gợi ý rằng - đối với email tiêu biểu của tôi - một chiến lược sử dụng instanceof để loại bỏ đầu tiên Strings là tốt nhất.

Trong số các chuỗi, 394 là văn bản/đồng bằng và 5 là văn bản/html. Điều này sẽ không phải là trường hợp cho hầu hết; nó phản ánh nguồn cấp dữ liệu email của tôi vào hộp thư đến cụ thể này.

Nhưng hãy đợi - còn nhiều hơn nữa !!! :-) HTML lén lút trong đó tuy nhiên: của 87 Multipart, 70 là multipart/alternative. Không có bảo đảm, nhưng hầu hết (nếu không phải tất cả những điều này) là TEXT + HTML.

Trong số 17 multipart khác, ngẫu nhiên, 15 là nhiều phần/hỗn hợp và 2 là nhiều phần/ký.

Trường hợp sử dụng của tôi với hộp thư đến này (và một trường hợp khác) chủ yếu là tổng hợp và phân tích nội dung danh sách gửi thư đã biết. Tôi không thể bỏ qua bất kỳ thông điệp nào, nhưng phân tích về loại này giúp tôi xử lý hiệu quả hơn.

+0

Phản hồi tuyệt vời của Real World. Sự đa dạng của các đối tượng email hợp lệ là tuyệt vời ... mỗi máy chủ dường như có sở thích riêng của họ. – kevinarpe