Manually Interact with IMAP(s) Using Telnet or OpenSSL

Microsoft Exchange Random

Sometimes it can be handy to connect into an IMAP(s) server to verify it is working as expected, or to view emails via a command line interface. In this example I’m connecting to a Microsoft Exchange 2016 Server with IMAP enabled, specifically IMAPS, so running on port 993.

Connect and Login

Firstly we need to connect and login:

openssl s_client -crlf -connect mail.example.org:993

Once connected, you can login. Notice the “a” at the front of the line, this is needed or you’ll get the following error: LOGIN BAD Command Error. 12

a LOGIN username password

List Folder Structure

Once you are connected, you can then view a list folders by using the following:

a LIST "" "*"

Okay, so in the list we can see our “Inbox”, it will appear like:

* LIST "INBOX/" "*"

We can see the folder structure (if there is one) within “Inbox” and we can also see that there are 31 messages in the root of the “Inbox”. Let’s have a look into it with:

a EXAMINE "INBOX/"
a OK LIST completed.
a EXAMINE INBOX
* 31 EXISTS
* FLAGS (\Seen \Answered \Flagged \Deleted \Draft $MDNSent)
* OK [PERMANENTFLAGS ()] Permanent flags
* OK [UNSEEN 23] Is the first unseen message
* OK [UIDVALIDITY 14] UIDVALIDITY value
* OK [UIDNEXT 239318] The next unique identifier value
a OK [READ-ONLY] EXAMINE completed.

So we can see that there are 31 emails in the “Inbox”.

Select and Fetch Messages

Let’s SELECT the “Inbox” with the below. EXAMINE is the same as SELECT, however the former is read-only, the latter sets the future commands to use this folder as the target.

a SELECT "INBOX/"

Let’s fetch the first 5 messages in the “Inbox”, getting the subject of these messages:

f fetch 1:5 (BODY[HEADER.FIELDS (Subject)])

Nice, so let’s get more of the header fields, to help us see all the messages, we’ll retrieve the Subject, Date and From fields, as per the below:

f fetch 1:5 (BODY[HEADER.FIELDS (Subject Date From)])

We get an output like:

From: Bob Smith <bob@domain.com>
Subject: A test message 1
Date: Fri, 21 Jun 2024 15:04:08 +0100

)
* 2 FETCH (BODY[HEADER.FIELDS (Subject Date From)] {174}
From: Bob Smith <bob@domain.com>
Date: Thu, 10 Oct 2024 13:17:51 +0000
Subject: A test message 2
 [EXT]

)
* 3 FETCH (BODY[HEADER.FIELDS (Subject Date From)] {121}
From: Bob Smith <bob@domain.com>
Subject: A test message 3
Date: Wed, 16 Oct 2024 14:56:35 +0000

)
* 4 FETCH (BODY[HEADER.FIELDS (Subject Date From)] {167}
From: Bob Smith <bob@domain.com>
Subject: A test message 4
Date: Mon, 11 Nov 2024 11:02:27 +0000

)
* 5 FETCH (BODY[HEADER.FIELDS (Subject Date From)] {136}
From: Bob Smith <bob@domain.com>
Subject: A test message 5
Date: Mon, 18 Nov 2024 15:33:08 +0000

)
f OK FETCH completed.

You’ll notice that the messages are showing up in reverse date order.

One problem with using FETCH is that it marks the messages as “Seen” i.e. read. If we don’t want to do this, we can use .PEEK, such as:

f fetch 1:5 (BODY.PEEK[HEADER.FIELDS (Subject Date From)])

Read a Message

So finally, let’s open and read one of the messages, there are few bits we can do here. One thing to note is we’re reading in plain text, there is no formatting (for HTML) so we’ll see lots of seemingly superfluous information, unless of course everyone who sends you email does so in plain text! We’ll use the “.PEEK” on the end, so it doesn’t mark the message as read.

a FETCH 1 BODY.PEEK[TEXT]
a FETCH 1 BODY.PEEK[HEADER]
a FETCH 1 BODY.PEEK[]

Close/Logout Session

When you are done:

a LOGOUT

Leave a Reply

Your email address will not be published. Required fields are marked *