Writing a Gmail client on PHP (POP3 and IMAP)

Let’s create a Gmail email client using PHP’s native IMAP library.

For this, you need the php-imap installed.

Despite the name, the IMAP library works with POP3 too.

Basic code:

Return Example:

That’s it!


The example above connects through IMAP. If you prefer POP3, use this:


Username: Your email.
Ex: “[email protected]“. It can be a custom domain, like “[email protected]“.

Password: Your account password.
For 2-step verification accounts, you can use an “app password“. These are extra passwords to access your account. With them, you don’t need to share your actual password with your apps. For each app, you create a new “app password”. This is only available if “2-step” is enabled.


Each message has a msgno, which is a sequential number. The very first message is 1. This number is unique for your mailbox. Even if you delete a message, its msgno won’t be reused.

The msgno is used in many commands.

Retrieving emails:

As we saw previously, that’s how we get the messages:

$range format is: {msgno_from}:{msgno_to}. The msgno_from and msgno_to are included in the response.

Range examples:

  • All messages: ‘1:*’
  • Just message #3: ‘3’
  • Message #3 and beyond (3,4,5,…): ‘3:*’;

Use the range argument to create savepoints, i.e. if you want to download only the new messages and not the whole inbox each time your app syncs with Gmail. To create savepoints, download all messages (1:*) on the first time and save the last message number (“msgno“), ex. “5”. Next time, you check from that message and beyond (6:*).

Display Name (From/To):

The “From” and “To” fields support a display name in addition to the email address:

Closing the connection:

You should close the email connection after using it, which is usually at the end of your script.

If you forget to close, PHP will automatically close it for you when the script ends, but it is a good idea to explicitly close it with:


To get an array with past errors, use:

Return example: 

To get only the last error, use imap_last_error().

If you don’t retrieve errors by calling these functions, then all errors and warnings will be thrown when the connection gets closed.

Replying to an email:

Each message has a message_id, which is a universal unique identifier.

To reply to messages, you need to set 2 things:

  1. Headers: Send the message_id of the message you are replying to in two header items: In-Reply-To and References;
  2. Subject: The subject should be postfixed with the same subject as the original message. Example of valid reply subjects: {$subject} or Re: {$subject} or Reply to {$subject}. It actually doesn’t matter if you prefix with something (like “Re:”) or not, the only rule is that you need to end the subject with the original copy;

Example of a replied message:

If you are curious of how a replied message looks like when retrieving it:

Notice the “subject”, the “references” and the “in_reply_to” fields.

Which email address you should reply to?

You can reply to the email address specified in the “From” field, but if the sender has set a “reply-to”, your message will go the wrong place.

To reply properly, you should get the headers with imap_headerinfo($hnd, $msgno) and use the reply_toaddress property (a string). Alternatively, you can use the reply_to property, which returns the email parsed as domain, account and display_name.

It is safe to always use the “reply_toaddress” property (or the “reply_to”) even if the sender hasn’t set a reply-to. In these cases, “reply_toaddress” will return the same value as “from”.

Close Menu