Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Mail Slow downloading attachment Office 365

I am reading the inbox of an office 365 Mail account and downloading the attachment of it (txt files). It works fine with small files less than 2 MB but when I tried with a 20 MB file, It is really slow. I test the code in two different machines (Linux and Windows) and the speed was the same, really slow.

String user = "[email protected]";
String password = "mypassword";
try{

    boolean foundSites = false;

    // Get a Properties object
    Properties properties = new Properties();

    properties.put("mail.imaps.host", host);
    properties.put("mail.imaps.port", port);
    properties.put("mail.imaps.starttls.enable", SSL);
    //properties.put("mail.imap.fetchsize", "1000000");
    Session emailSession = Session.getDefaultInstance(properties);

    //create the POP3 store object and connect with the pop server
    Store store = emailSession.getStore("imaps");
    store.connect(host, user, password);

    //create the folder object and open it
    Folder emailFolder = store.getFolder("INBOX");
    emailFolder.open(Folder.READ_ONLY);

    // retrieve the messages from the folder in an array and print it
    Message[] messages = emailFolder.getMessages();
    System.out.println("messages.length---" + messages.length);

    LocalDateTime now = LocalDateTime.now();
    int year = now.getYear();
    int month = now.getMonthValue();
    int day = now.getDayOfMonth();

    for (int i = messages.length - 1; i >= 0; i--) {
    Message message = messages[i];


    Calendar cal = Calendar.getInstance();
    cal.setTime(message.getReceivedDate());
    int yearMessage = cal.get(Calendar.YEAR);
    int monthMessage = cal.get(Calendar.MONTH) + 1;
    int dayMessage = cal.get(Calendar.DAY_OF_MONTH);



    if(year == yearMessage && month == monthMessage && day == dayMessage)
    {
        //The real code is doing this with 20 Subjects (20 emails)
        if(message.getSubject().equalsIgnoreCase("Integration - Site Info") && foundSites != true)
        {
            System.out.println("found Integration - Site Info");

            Multipart multipart = (Multipart) message.getContent();
            List<File> attachments = new ArrayList<>();
            for (int j = 0; j < multipart.getCount(); j++) {
                BodyPart bodyPart = multipart.getBodyPart(j);
                if(Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition()))
                {
                    InputStream is = bodyPart.getInputStream();
                    File f = new File("./attachments/"
                            + "sites_"+Integer.toString(day)+"-"+Integer.toString(month)+"-"+Integer.toString(year)+".csv");
                    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);
                    foundSites = true;
                    break;
                }


            }
        }
    }

    if(foundSites)
    {
        break;
    }
} catch (Exception e) {
    System.out.println(e);  
}

I can possibly create threads, but is there any other alternative?

Just a side note: I try the code with python and the speed improve significantly.

====================================== UPDATE 1:

I did the change to saveFile method and the code simplifies a lot, but still the same downloading speed of 10 KB per second.

MimeBodyPart bodyPart = (MimeBodyPart) multipart.getBodyPart(j);
if(Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition()))
{
    bodyPart.saveFile("./attachments/"
        + "sites_"+Integer.toString(day)+"-"+Integer.toString(month)+"-"+Integer.toString(year)+".csv");

I also use the profiler and the results are: enter image description here

enter image description here

like image 749
Christian Salvador Avatar asked Mar 10 '23 16:03

Christian Salvador


1 Answers

Fix these common mistakes.

Simplify your code by using MimeBodyPart.saveFile to save the attachment.

Since you're using the "imaps" protocol and not the "imap" protocol, set the mail.imaps.fetchsize property to something large enough to get the performance you want without using more memory than you want to use. Or set mail.imaps.partialfetch to false if you don't care how much memory you use and you're sure you'll always have enough.

like image 128
Bill Shannon Avatar answered Mar 23 '23 14:03

Bill Shannon