Dejan Stošić

Web Developer

Hello, i'm Dejan Stošić, part-time web developer and part-time computer science student. Welcome to my blog!


PHP imap_open() too slow? Here is the solution

Intro

The handy PHP function for connecting to IMAP servers, the imap_open(), caused nothing but trouble for me for the past few days. And, like it usually is, the stupidest problems are the hardest to solve.

<?php  
    $mbox = imap_open('{imap.example.com:993/imap/ssl}', "mail@example.com", "password");

    imap_close($mbox)
?>

This is the code i started running my tests with - just the opening and closing of connection without any operations in between took insanely long:

  • 30 seconds on my localhost - Windows 7

  • 40 seconds on my shared host (Justhost) - Unknown Linux distro

  • <1 second on my VPS (DigitalOcean) - Ubuntu 14.04

I tried to connect to 3 different mailboxes, Gmail, Microsoft Outlook and one hosted on my shared host - results were still similiar!

To make the things worse, there was very little to none help about this issue on the internet, lots of people were encountering the long execution times of imap_open(), yet few could find the solution. And after few days of messing around with various settings i came to

Why DNS, why?!

Turns out the issue was all along with the DNS! For some reason Domain Name Servers took waaay too long to resolve the domains of IMAP servers.

This was the issue in my case. To test if you have the same issue too open up your terminal/command line and type

ping imap.google.com

Replace the imap.google.com with the domain of IMAP server you are trying to connect to

If your ping requests take too long or time out then you have the same issue!

Now that we know where is the problem, we can solve it!

Solution A - Modifying Hosts File

The best and simplest way is to modify your hosts file. Hosts file is used by an operating system to map hostnames to IP addresses - if there is IP address - domain pair in the hosts file, you won't have to connect to DNS server to get the IP address, your OS directly returns the IP of a requested domain.

Step 1)

Using some tool like GetIP or PHP function gethostbyname() determine the IP address of your IMAP domain.

Example: For imap.gmail.com the IP is 173.194.68.108

Step 2)

Open your hosts file:

Windows - located in C:\Windows\System32\drivers\etc\hosts

Linux / Mac OS - located in etc/hosts

Step 3)

At the end of the hosts file insert your newly discovered IP - domain pair. Save the file and you are done, it should work much faster!

Example: 173.194.68.108 imap.gmail.com



Solution B - Passing IP address directly

If you are stuck with shared host, unfortunately you won't have access to hosts file. Another solutions is to pass the IP address directly to imap_open() like this and pray that it will work:

<?php  
    $mbox = imap_open('{173.194.68.108:993/imap/ssl}', "mail@example.com", "password");

    imap_close($mbox)
?>

Why pray? Because in some cases (depending on the IMAP server) connecting to IP address directly will cause the certificate authentication fail and the connection will be rejected. You can add the /novalidate-cert to the connection string and it will work. Like this:

<?php  
    $mbox = imap_open('{173.194.68.108:993/imap/ssl/novalidate-cert}', "mail@example.com", "password");

    imap_close($mbox)
?>

but you must be aware that this makes your script prone to Man in the middle attack!

I hope this article could help you!

comments powered by Disqus