<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: jrpereirajr</title>
    <description>The latest articles on DEV Community by jrpereirajr (@jrpereirajr).</description>
    <link>https://dev.to/jrpereirajr</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F551070%2Ffd0fbc61-9370-44eb-96a7-6c3b76e1e45d.jpg</url>
      <title>DEV Community: jrpereirajr</title>
      <link>https://dev.to/jrpereirajr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jrpereirajr"/>
    <language>en</language>
    <item>
      <title>Implementing an IMAP Client in InterSystems IRIS - part II</title>
      <dc:creator>jrpereirajr</dc:creator>
      <pubDate>Sat, 12 Feb 2022 15:29:51 +0000</pubDate>
      <link>https://dev.to/intersystems/implementing-an-imap-client-in-intersystems-iris-part-ii-3obd</link>
      <guid>https://dev.to/intersystems/implementing-an-imap-client-in-intersystems-iris-part-ii-3obd</guid>
      <description>&lt;p&gt;In the first part we got a quick introduction on the IMAP protocol commands, now it's time to use IRIS and implement them and create our own IMAP client!&lt;/p&gt;

&lt;h2&gt;
  
  
  IRIS Email Framework
&lt;/h2&gt;

&lt;p&gt;The IRIS platform has default interfaces and classes for working with email. Developers originally designed those artifacts for POP3 implementation. However, this doesn’t mean that we can’t use and extend these interfaces and classes to implement an IMAP client. So let’s talk about them:&lt;/p&gt;

&lt;p&gt;%Net.Fetch&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MailProtocol: This is the base class for email retrieval. The IMAP client extends it.&lt;/li&gt;
&lt;li&gt;%Net.MailMessage: This is the MIME message. It extends %Net.MailMessagePart.&lt;/li&gt;
&lt;li&gt;%Net.MailMessagePart: This encapsulates a MIME message part for multipart messages. This class has an array for itself, enabling a tree representation of message subparts.&lt;/li&gt;
&lt;li&gt;%Net.MIMEReader: This utility class has methods to parse a message’s MIME content, generating a %Net.MIMEPart instance.&lt;/li&gt;
&lt;li&gt;%Net.MIMEPart: This encapsulates the message’s MIME parts and provides methods to get information about them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementing an IMAP Client
&lt;/h2&gt;

&lt;p&gt;In this section, we present implementation details about an IMAP client, an inbound interoperability adapter, and a simple production example. Note that, in favor of saving space, we won’t show most implementation methods. Instead, we link to each one’s full implementation details. You can find the complete source code on &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Basic IMAP Client
&lt;/h2&gt;

&lt;p&gt;As we discussed before, IMAP is a plain text-based protocol over TCP. This means the base code to implement a client for such a protocol is a TCP client.&lt;/p&gt;

&lt;p&gt;The IRIS platform provides standard ObjectScript &lt;a href="https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GIOD_IODEVCOMMS" rel="noopener noreferrer"&gt;commands to perform I/O operations&lt;/a&gt;: OPEN, USE, READ, WRITE, and CLOSE.&lt;/p&gt;

&lt;p&gt;Here is a simple example of how to connect to the MS Outlook server, log in, then log out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ClassMethod SimpleTest()
{
    // connection configuration
    SET dev = "|TCP|993"
    SET host = "outlook.office365.com"
    SET port = "993"
    SET mode = "C"
    SET sslConfig = "ISC.FeatureTracker.SSL.Config"
    SET timeout = 30
    // connection to MS Outlook IMAP server
    OPEN dev:(host:port:mode:/TLS=sslConfig):timeout
    THROW:('$TEST) ##class(%Exception.General).%New("Sorry, can't connect...")
    USE dev
    READ resp($INCREMENT(resp)):timeout
    WRITE "TAG1 LOGIN user@outlook.com password", !
    READ resp($INCREMENT(resp)):timeout
    WRITE "TAG2 LOGOUT", !
    READ resp($INCREMENT(resp)):timeout
    CLOSE dev
    // come back to default device (terminal) and prints responses
    USE 0
    ZWRITE resp
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is its output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;USER&amp;gt;d ##class(dc.Demo.Test).SimpleTest()
resp=3
resp(1)="* OK The Microsoft Exchange IMAP4 service is ready. [QwBQ..AA==]"_$c(13,10)
resp(2)="TAG1 OK LOGIN completed."_$c(13,10)
resp(3)="* BYE Microsoft Exchange Server IMAP4 server signing off."_$c(13,10)_"TAG2 OK LOGOUT completed."_$c(13,10)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are some highlights in this code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We set the mode variable to C, which is carriage return mode. This setting is mandatory for IMAP.&lt;/li&gt;
&lt;li&gt;The flag /TLS establishes a secure layer of communication (SSL). We must set this flag value to a valid SSL IRIS connection.&lt;/li&gt;
&lt;li&gt;The OPEN command initiates the connection.&lt;/li&gt;
&lt;li&gt;The special boolean variable $TEST returns 1 when a command with a timeout is successful or 0 if the timeout expires. In this example, if the OPEN command exceeds 30 seconds, the code throws an exception.&lt;/li&gt;
&lt;li&gt;After a connection is established successfully, the command USE owns the TCP device, redirecting all READ and WRITE commands to this device.&lt;/li&gt;
&lt;li&gt;The WRITE command issues commands to the IMAP server, and the READ command gets their output.&lt;/li&gt;
&lt;li&gt;To finish the connection, we must use the CLOSE command.&lt;/li&gt;
&lt;li&gt;After owning the device, all calls to READ and WRITE commands execute on the device specified in the dev variable, after using the USE dev command. To come back to the terminal and write to it again, you need to issue a USE 0 command first.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each READ command has a limited buffer to store the server response. When the response size exceeds this limit, you need to issue another READ command to read the complete response. Of course, it’s possible to increase the buffer size, but a better approach is to be ready to deal with such a situation.&lt;/p&gt;

&lt;p&gt;As we discussed before, IMAP requires a tag for each command. This tag is helpful to check if the code retrieved the complete response or if it needs to issue another READ command. In this case, we implement the &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAPHelper.cls#L77" rel="noopener noreferrer"&gt;ReadResponse &lt;/a&gt;method to ensure the code reads the whole message.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing the %Net.FetchMailProtocol Interface for IMAP
&lt;/h2&gt;

&lt;p&gt;The %Net.FetchMailProtocol abstract class abstracts email retrieval on the IRIS platform. We implement the following methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connect: This establishes a connection to the IMAP server and logs in a user.&lt;/li&gt;
&lt;li&gt;GetMailBoxStatus: This gets the size of the mailbox and how many messages are in it.&lt;/li&gt;
&lt;li&gt;GetSizeOfMessages: This gets the size of one or all messages identified by a message number.&lt;/li&gt;
&lt;li&gt;GetMessageUIDArray: This gets an array with one or all message UIDs in the inbox.&lt;/li&gt;
&lt;li&gt;GetMessageUID: This gets the UID corresponding to a message number.&lt;/li&gt;
&lt;li&gt;Fetch: This retrieves a message’s content, possibly multipart content, identified by a message number. It retrieves the message content encapsulated in a %Net.MailMessage object.&lt;/li&gt;
&lt;li&gt;FetchFromStream: This is the same as Fetch, but gets content from an encapsulated EML message content in a %BinaryStream object, instead of calling the IMAP server.&lt;/li&gt;
&lt;li&gt;FetchMessage: This is the same as Fetch, but returns specific message headers in ByRef variables.&lt;/li&gt;
&lt;li&gt;FetchMessageInfo: This retrieves only message headers and the text of the message.&lt;/li&gt;
&lt;li&gt;DeleteMessage: This adds a message to the deletion array.&lt;/li&gt;
&lt;li&gt;RollbackDeletes: This cleans up the deletion array.&lt;/li&gt;
&lt;li&gt;QuitAndCommit: This deletes all messages in the deletion array and disconnects from the IMAP server.&lt;/li&gt;
&lt;li&gt;QuitAndRollback: This cleans up the deletion array and disconnects from the IMAP server.&lt;/li&gt;
&lt;li&gt;Ping: This pings the IMAP server to keep the session alive.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, we create a new class to implement the interface: &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L1" rel="noopener noreferrer"&gt;dc.Demo.IMAP&lt;/a&gt;. This class inherits several properties, which we must set to establish a connection to the IMAP server. &lt;/p&gt;

&lt;p&gt;We create a helper class as well: &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAPHelper.cls#L2" rel="noopener noreferrer"&gt;dc.Demo.IMAPHelper&lt;/a&gt;. This class parses methods for IMAP responses, gets all parts of a multipart message, and stores peripheral features, including a method to send commands and ensure the entire response is read.&lt;/p&gt;

&lt;p&gt;The first method we implement is the &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L63" rel="noopener noreferrer"&gt;Connect&lt;/a&gt; method. This method establishes a connection to the IMAP server using the configuration encapsulated in the class properties. It issues a login as well. This method uses the IRIS platform’s OPEN command to establish the connection to the IMAP server and the IMAP command LOGIN to authenticate to the server.&lt;/p&gt;

&lt;p&gt;The next method we implement is &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L116" rel="noopener noreferrer"&gt;GetMailBoxStatus&lt;/a&gt;. This method uses the SELECT command to select a mailbox and it brings some additional information as well, like how many messages are in the mailbox.&lt;/p&gt;

&lt;p&gt;IMAP doesn’t have a ready-to-use command to get the size of all messages. Of course, it’s possible to iterate through all messages and sum their sizes. However, this strategy will probably cause slowness issues. So in this implementation, we don’t retrieve the size for all messages.&lt;/p&gt;

&lt;p&gt;The next method is &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L150" rel="noopener noreferrer"&gt;GetSizeOfMessages&lt;/a&gt;. This method gets the size of one or more messages in the inbox. When no message number is defined, this method throws an exception due to the same IMAP limitation we explained for the &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L116" rel="noopener noreferrer"&gt;GetMailBoxStatus&lt;/a&gt; method. We use the IMAP command FETCH  (RFC822.SIZE) to retrieve a message size by its number.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L208" rel="noopener noreferrer"&gt;GetMessageUIDArray&lt;/a&gt; method comes next, which uses the IMAP commands SELECT and UID SEARCH [ALL | ] and parses its response to get the UID array.&lt;/p&gt;

&lt;p&gt;The next method is &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L268" rel="noopener noreferrer"&gt;GetMessageUID&lt;/a&gt;. This method gets a UID for a defined message number and uses the same logic as the &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L208" rel="noopener noreferrer"&gt;GetMessageUIDArray&lt;/a&gt; method.&lt;/p&gt;

&lt;p&gt;Following this is the &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L294" rel="noopener noreferrer"&gt;Fetch&lt;/a&gt; method. It uses the IMAP commands SELECT and FETCH  BODY to retrieve message content, which is coded in MIME format. Fortunately, the IRIS platform has a reader for &lt;a href="https://developer.mozilla.org/pt-BR/docs/Web/HTTP/Basics_of_HTTP/MIME_types" rel="noopener noreferrer"&gt;MIME&lt;/a&gt; content, the %Net.MIMEReader class. This class gets the message in a stream and returns the parsed message in a %Net.MIMEPart object.&lt;/p&gt;

&lt;p&gt;After getting the MIME content, the method creates a %Net.MailMessage object, fills it with data from the %Net.MIMEPart object, and returns it.&lt;/p&gt;

&lt;p&gt;The MIME content is encapsulated in a %Net.MIMEPart object that maps into a %Net.MailMessagePart object through the &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAPHelper.cls#L172" rel="noopener noreferrer"&gt;GetMailMessageParts&lt;/a&gt; method in the &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAPHelper.cls#L2" rel="noopener noreferrer"&gt;dc.Demo.IMAPHelper&lt;/a&gt; class.&lt;/p&gt;

&lt;p&gt;The next method is &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L361" rel="noopener noreferrer"&gt;FetchFromStream&lt;/a&gt;. This method receives a stream object with an EML message and converts it to a %Net.MailMessage object. This method does not retrieve content from the server.&lt;/p&gt;

&lt;p&gt;Following are the &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L424" rel="noopener noreferrer"&gt;FetchMessage&lt;/a&gt; and &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L461" rel="noopener noreferrer"&gt;FetchMessageInfo&lt;/a&gt; methods, which are special cases of the Fetch method.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L512" rel="noopener noreferrer"&gt;DeleteMessage&lt;/a&gt; method marks a message for deletion, whereas the [RollbackDeletes}(&lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L526" rel="noopener noreferrer"&gt;https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L526&lt;/a&gt;) method just cleans up the array of messages marked for deletion.&lt;/p&gt;

&lt;p&gt;Next is the &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L542" rel="noopener noreferrer"&gt;QuitAndCommit&lt;/a&gt; method. It disconnects from the IMAP server and calls the method &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L595" rel="noopener noreferrer"&gt;CommitMarkedAsDeleted&lt;/a&gt; for message deletion.&lt;/p&gt;

&lt;p&gt;The method &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/main/src/dc/Demo/imap/IMAP.cls#L552" rel="noopener noreferrer"&gt;QuitAndRollback&lt;/a&gt; just disconnects from the IMAP server and cleans up the array of messages marked for deletion.&lt;/p&gt;

&lt;p&gt;The last method, &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L581" rel="noopener noreferrer"&gt;Ping&lt;/a&gt;, issues a NOOP command to keep the IMAP session alive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing an Inbound Interoperability Adapter for IMAP
&lt;/h2&gt;

&lt;p&gt;The base class for email interoperability inbound in the IRIS platform is EnsLib.EMail.InboundAdapter. This inbound adaptor requires these configurations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The email server host address&lt;/li&gt;
&lt;li&gt;The email server port&lt;/li&gt;
&lt;li&gt;A credential ID which stores the username and password for accessing the server&lt;/li&gt;
&lt;li&gt;An SSL configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This class was extended to create a new IMAP inbound adapter class: &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAPInboundAdapter.cls#L2" rel="noopener noreferrer"&gt;dc.Demo.IMAPInboundAdapter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To use this new adapter, we set which mailbox to use in the Mailbox production parameter. Its default value is INBOX.&lt;/p&gt;

&lt;p&gt;The implementation is simple, it just overrides the MailServer property and sets its type to &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/POP3ToIMAPAdapter.cls#L5" rel="noopener noreferrer"&gt;dc.Demo.POP3ToIMAPAdapter&lt;/a&gt; IMAP client. This adapter maps the POP3 flow to the IMAP one, as the base adapter class was designed for POP3 commands.&lt;/p&gt;

&lt;p&gt;Thus, this POP3 to IMAP adapter enables us to perform all the original inbound adapter logic using IMAP commands instead of POP3 commands.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/POP3ToIMAPAdapter.cls#L5" rel="noopener noreferrer"&gt;dc.Demo.POP3ToIMAPAdapter&lt;/a&gt; class, we use the IMAP client IMAPClient of type &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L4" rel="noopener noreferrer"&gt;dc.Demo.IMAP&lt;/a&gt; as a proxy for server communication. However, as &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/POP3ToIMAPAdapter.cls#L5" rel="noopener noreferrer"&gt;dc.Demo.POP3ToIMAPAdapter&lt;/a&gt; extends %Net.POP3, it must override all abstract methods in %Net.FetchMailProtocol.&lt;/p&gt;

&lt;p&gt;Also, we had to implement new methods that the %Net.POP3 client had implemented directly: &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/POP3ToIMAPAdapter.cls#L47" rel="noopener noreferrer"&gt;ConnectPort&lt;/a&gt; and &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/POP3ToIMAPAdapter.cls#L54" rel="noopener noreferrer"&gt;FetchMessageHeaders&lt;/a&gt;. In the same way, we created &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/POP3ToIMAPAdapter.cls#L25" rel="noopener noreferrer"&gt;ConnectedGet&lt;/a&gt; and &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/POP3ToIMAPAdapter.cls#L31" rel="noopener noreferrer"&gt;SSLConfigurationSet&lt;/a&gt; methods to set and get properties that  %New.POP3 also implemented directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a Simple Production
&lt;/h2&gt;

&lt;p&gt;To make all these classes work together, we set up a simple production. Check out &lt;a href="https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=ECONFIG_PRODUCTION" rel="noopener noreferrer"&gt;Creating a Production&lt;/a&gt; to get more information about IRIS Interoperability productions.&lt;/p&gt;

&lt;p&gt;This production includes a &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter/blob/eb0218fbe46893f8e49d43f7d2612deab0d642f6/src/dc/Demo/IMAPTestService.cls#L1" rel="noopener noreferrer"&gt;business service&lt;/a&gt; and a &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter/blob/eb0218fbe46893f8e49d43f7d2612deab0d642f6/src/dc/Demo/IMAPTestSendEmailOperation.cls#L1" rel="noopener noreferrer"&gt;business operation&lt;/a&gt;, which uses the IMAP inbound adapter to check for new messages. This code was inspired by the &lt;a href="https://docs.intersystems.com/latest/csp/documatic/%25CSP.Documatic.cls?&amp;amp;LIBRARY=ENSDEMO&amp;amp;PRIVATE=1&amp;amp;CLASSNAME=Demo.Loan.FindRateProduction" rel="noopener noreferrer"&gt;Demo.Loan.FindRateProduction&lt;/a&gt; interoperability sample.&lt;/p&gt;

&lt;p&gt;In short, this production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses the &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L208" rel="noopener noreferrer"&gt;GetMessageUIDArray&lt;/a&gt; method to get all available messages in the configured mailbox&lt;/li&gt;
&lt;li&gt;Loops over them, tracing their output, fetched by the &lt;a href="https://github.com/jrpereirajr/iris-imap-inbound-adapter-demo/blob/c477d3b37b2ff63824ab66bebb61d18017d449db/src/dc/Demo/imap/IMAP.cls#L294" rel="noopener noreferrer"&gt;Fetch&lt;/a&gt; method&lt;/li&gt;
&lt;li&gt;Checks if each message subject matches a criterion — starting with "[IMAP test]"&lt;/li&gt;
&lt;li&gt;Responds to the sender if the message subject matches the criteria, otherwise ignores the message&lt;/li&gt;
&lt;li&gt;Deletes all of the messages so that it won’t analyze them again&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FT4TbF2XuljgKR6ZN6lLNMkfE3k-1b-3oo1RUe3oKcX4R-CJ9cskhR0iK9GCXP3ZHNRCaahQIOBROrB1BxR0NtYqN1bZUbvBQXoUpWWwNG1aUdq0fbEKYRdHkIc6Tnud2JCEpoxy2%3Ds0" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FT4TbF2XuljgKR6ZN6lLNMkfE3k-1b-3oo1RUe3oKcX4R-CJ9cskhR0iK9GCXP3ZHNRCaahQIOBROrB1BxR0NtYqN1bZUbvBQXoUpWWwNG1aUdq0fbEKYRdHkIc6Tnud2JCEpoxy2%3Ds0" alt="IRIS Interoperability production configuration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this example, we configure an IMAP server from Yahoo Mail imap.mail.yahoo.com, on port 993. We also use the default IRIS SSL configuration “ISC FeatureTacker.SSL.Config”.&lt;/p&gt;

&lt;p&gt;Next, we configure a credential called imap-test containing a username and password, as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FIx3Ghl0tIni9Z7aReZVYWawvUdWGbPertNRjBAoHJc0FtCot2pTbTYwDUK2Wer4xtSVh4woeNrp8hWiUU8VabkAuMRFQIzFXjACCgWwRhvpS_0UI1ziBcM1HaidFZuyq5UmQaaHF%3Ds0" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FIx3Ghl0tIni9Z7aReZVYWawvUdWGbPertNRjBAoHJc0FtCot2pTbTYwDUK2Wer4xtSVh4woeNrp8hWiUU8VabkAuMRFQIzFXjACCgWwRhvpS_0UI1ziBcM1HaidFZuyq5UmQaaHF%3Ds0" alt="Credentials Viewer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the image below shows, the production starts and keeps querying the IMAP server for new messages. When there are new messages, the inbound adapter grabs their information, like the header and subject, and lets production take further action based on this information.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2F7LQnaj53wY1ndZu6dwLUktUEm6nlATaVu9Z1S-x8dDxaLXk4dz0KXV9vgL5yxuIzJlSfu0mNsQicdpIPl9UK5bf8GQZsNbmMp7CtNn80l4jaaRftGMCakLMF5IOSFLqCxawxKlK2%3Ds0" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2F7LQnaj53wY1ndZu6dwLUktUEm6nlATaVu9Z1S-x8dDxaLXk4dz0KXV9vgL5yxuIzJlSfu0mNsQicdpIPl9UK5bf8GQZsNbmMp7CtNn80l4jaaRftGMCakLMF5IOSFLqCxawxKlK2%3Ds0" alt="Event Log"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this example, the production checks if the message subject starts with "[IMAP test]" and sends back a message to the sender.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FAMZc7lIhwfV9VNxeP0m8A2YWcebRqFMwwKGFLz8wwTRQImHUZgsd8LetMc_IRmUVLItnz1D1l5Y3IoUYVUUOsxoZSqsGgX_Q_g0_q3SXoh5spVvZ-aieZL7IcpDGe1iI1xCJYAu-%3Ds0" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FAMZc7lIhwfV9VNxeP0m8A2YWcebRqFMwwKGFLz8wwTRQImHUZgsd8LetMc_IRmUVLItnz1D1l5Y3IoUYVUUOsxoZSqsGgX_Q_g0_q3SXoh5spVvZ-aieZL7IcpDGe1iI1xCJYAu-%3Ds0" alt="Event Log"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FtB7iNeO1-uIoLeQB5614I08fRnee9lg5gdadN9dUAWkw0o3jxPWQf4_a3m850HYFlDv17NQCjI448_7oU6aTd3ZwNZyUgo7v1bsM4oKa6z2jrMUfR3Nlc91inwsL5tpyQj-S8_5J%3Ds0" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FtB7iNeO1-uIoLeQB5614I08fRnee9lg5gdadN9dUAWkw0o3jxPWQf4_a3m850HYFlDv17NQCjI448_7oU6aTd3ZwNZyUgo7v1bsM4oKa6z2jrMUfR3Nlc91inwsL5tpyQj-S8_5J%3Ds0" alt="E-mail inbox"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a message doesn’t match the criteria, production just ignores it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FbRrA--2REgdldK2AAojGwDi-X4K1kThiLX1TOm69kaC27oSKsfh52ABrDs7G3KVJ1al6A6SkzDwf9mkeYD0cL9vnUfbbBIwvoRIgBf1cNPHfk9qBvopzUGK21lbfIRp6r5kksqCs%3Ds0" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FbRrA--2REgdldK2AAojGwDi-X4K1kThiLX1TOm69kaC27oSKsfh52ABrDs7G3KVJ1al6A6SkzDwf9mkeYD0cL9vnUfbbBIwvoRIgBf1cNPHfk9qBvopzUGK21lbfIRp6r5kksqCs%3Ds0" alt="Event Log"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we discussed an IMAP client implementation. First, we explored some essential background on IMAP and its main commands. Then, we detailed the implementation, covering the client itself and how to connect it to the IRIS platform. We also presented an extension to the default interoperability adapter to use IMAP, and a simple production example.&lt;/p&gt;

&lt;p&gt;Now that you know more about IMAP and its settings and you know how to connect it to IRIS, you can set up email capabilities in your applications. To learn more about the IMAP topics we discussed here, explore the resources below.&lt;/p&gt;

&lt;p&gt;Resources&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.atmail.com/blog/imap-101-manual-imap-sessions/" rel="noopener noreferrer"&gt;Atmail’s IMAP 101: Manual IMAP Sessions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fastmail.help/hc/en-us/articles/360060591353-Why-is-IMAP-better-than-POP-" rel="noopener noreferrer"&gt;Fastmail’s Why is IMAP better than POP?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc3501" rel="noopener noreferrer"&gt;IETF’s Internet Message Access Protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc2045" rel="noopener noreferrer"&gt;IETF’s Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=GIOD_iodevcomms" rel="noopener noreferrer"&gt;InterSystems’ I/O Devices and Commands&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=EEMA_inbound" rel="noopener noreferrer"&gt;InterSystems’ Using the Email Inbound Adapter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nylas.com/blog/nylas-imap-therefore-i-am" rel="noopener noreferrer"&gt;Nylas’ Everything you need to know about IMAP&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>interoperability</category>
      <category>imap</category>
      <category>intersystems</category>
    </item>
    <item>
      <title>Implementing an IMAP Client in InterSystems IRIS - part I</title>
      <dc:creator>jrpereirajr</dc:creator>
      <pubDate>Sat, 12 Feb 2022 15:29:38 +0000</pubDate>
      <link>https://dev.to/intersystems/implementing-an-imap-client-in-intersystems-iris-part-i-35hc</link>
      <guid>https://dev.to/intersystems/implementing-an-imap-client-in-intersystems-iris-part-i-35hc</guid>
      <description>&lt;p&gt;This article explains how to use the InterSystems IRIS platform to write a basic IMAP client. First, we present an overview of IMAP, then we discuss the main IMAP commands and client implementation. Finally, we offer a simple use of this IMAP client on the IRIS interoperability application.&lt;/p&gt;

&lt;p&gt;Note that this article isn’t a detailed IMAP explanation. For more detailed information, please check the references of this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  IMAP Overview
&lt;/h2&gt;

&lt;p&gt;The Internet Message Access Protocol (IMAP) lets users retrieve emails. Mark Crispin proposed IMAP in the 1980s, and since then, the protocol has been published and revised in &lt;a href="https://datatracker.ietf.org/doc/html/rfc3501"&gt;RFC 3501&lt;/a&gt;. At the time of writing this article, its current version is IMAP4rev1.&lt;/p&gt;

&lt;p&gt;It’s important to note that this protocol is designed for retrieving only. You must use another protocol, the Simple Mail Transfer Protocol (SMTP), if you need to send emails. There’s also an older protocol for email retrieval that’s as popular as IMAP, called Post Office Protocol version 3 (POP3).&lt;/p&gt;

&lt;h2&gt;
  
  
  Trying Basic IMAP Commands
&lt;/h2&gt;

&lt;p&gt;Like POP3, IMAP is a plaintext protocol. You can easily try some of its commands by yourself, using a TCP client like Telnet or OpenSSL.&lt;/p&gt;

&lt;p&gt;First, you need your IMAP host and email server port. For instance, at the time of writing this article, this is the host and port to connect to the Microsoft Outlook service:&lt;/p&gt;

&lt;p&gt;outlook.office365.com:993&lt;/p&gt;

&lt;p&gt;Let’s connect to this server using our TCP client. Enter the command below and hit ENTER. Note the use of the -crlf flag. This flag is mandatory for IMAP as carriage return and line feed (CRLF) is its line terminator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ openssl s_client -connect outlook.office365.com:993 -crlf -quiet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After you hit enter, the IMAP server shows you some information and stays waiting for input.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;depth=2 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert ...
* OK The Microsoft Exchange IMAP4 service is ready. [...]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can perform our first IMAP command: CAPACITY. As its name suggests, this command presents features that the server can provide. Note that the first line is the IMAP command itself, and the others lines are its output - this is the same for all other IMAP commands presented here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TAG1 CAPABILITY
* CAPABILITY IMAP4 IMAP4rev1 AUTH=PLAIN AUTH=XOAUTH2 SASL-IR UIDPLUS ID UNSELECT CHILDREN IDLE NAMESPACE LITERAL+
TAG1 OK CAPABILITY completed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the token before the CAPABILITY command: TAG1. A tag must precede every IMAP command and is any string you want. They identify what command instance the server is responding to. Generally, a simple counter with a prefix fits all your needs.&lt;/p&gt;

&lt;p&gt;The IMAP server finishes the response with the tag you used to issue the command and a flag indicating the command’s status, followed by miscellaneous information related to the command and status. The statuses allowed are: OK (success), NO (failure), and BAD (wrong command).&lt;/p&gt;

&lt;p&gt;The command LOGIN expects user and password as arguments. First, let’s check how the server responds if someone gives an invalid username and password:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TAG2 LOGIN user@outlook.com wrong-password
TAG2 NO LOGIN failed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the NO status after the command tag.&lt;/p&gt;

&lt;p&gt;Now, let’s proceed to a valid login:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TAG3 LOGIN user@outlook.com password
TAG3 OK LOGIN completed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we’re logged in. To finish our session, we use the LOGOUT command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TAG4 LOGOUT
* BYE Microsoft Exchange Server IMAP4 server signing off.
TAG4 OK LOGOUT completed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need other commands to implement our IMAP client, so we need to reconnect and log into our IMAP server again.&lt;/p&gt;

&lt;p&gt;Let’s get some information about the inbox next.&lt;/p&gt;

&lt;p&gt;First, we must tell the server which mailbox we want to access, INBOX in this case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TAG5 SELECT "INBOX"
* 14 EXISTS
* 0 RECENT
...
TAG5 OK [READ-WRITE] SELECT completed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are ready to access messages in our inbox, but we need a way to refer to them first. There are two ways to do that: by message number or by a unique identifier (UID).&lt;/p&gt;

&lt;p&gt;Message numbers are just counters, starting from 1 and going up to the number of messages within the inbox. When you delete a message, all following messages have their numbers decremented by 1. You can think of this as an array that has one of its elements removed.&lt;/p&gt;

&lt;p&gt;UIDs, on the other hand, keep their value whatever happens to the other messages.&lt;/p&gt;

&lt;p&gt;You can get UIDs using the UID SEARCH command. This command accepts a message number if you'd like to get a specific UID or the ALL parameter to get all UIDs in the directory.&lt;/p&gt;

&lt;p&gt;In the example below, we search for UID for message number 1, which is 483.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TAG6 UID SEARCH 1
* SEARCH 483
TAG6 OK SEARCH completed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s retrieve message information, like headers, body, and attachments. We use the FETCH command for this. This command has plenty of parameters, which you can explore in detail on &lt;a href="https://datatracker.ietf.org/doc/html/rfc3501"&gt;RFC 3501&lt;/a&gt;. In this article, we only address parameters related to the needs of the IMAP client implementation.&lt;/p&gt;

&lt;p&gt;The first information we need for this demonstration is the message size. We can get this information using the RFC822.SIZE parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TAG7 FETCH 1 RFC822.SIZE
* 1 FETCH (RFC822.SIZE 70988)
TAG7 OK FETCH completed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This indicates that the size of message number 1 is 70,988 bytes.&lt;/p&gt;

&lt;p&gt;Note that it’s also possible to use UIDs rather than message numbers to fetch message information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TAG8 UID FETCH 483 RFC822.SIZE
* 1 FETCH (RFC822.SIZE 70988 UID 483)
TAG8 OK FETCH completed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also get the basic From, To, Date, and Subject message headers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TAG9 FETCH 1 (FLAGS BODY[HEADER.FIELDS (FROM TO DATE SUBJECT)])
* 1 FETCH (FLAGS (\Seen) BODY[HEADER.FIELDS (FROM TO DATE SUBJECT)] {157}
Date: Thu, 22 Apr 2021 15:49:05 +0000
From: Another User &amp;lt;anotheruser@outlook.com&amp;gt;
To: user@outlook.com
Subject: Greetings from Another User!
 FLAGS (\Seen))
TAG9 OK FETCH completed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s retrieve the message body. We can retrieve all the body content using this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TAG10 FETCH 1 BODY[]
* 1 FETCH (BODY[] {9599}
...
MIME-Version: 1.0
--00000000000041bd3405c3403048
Content-Type: multipart/alternative; boundary="00000000000041bd3205c3403046"
--00000000000041bd3205c3403046
Content-Type: text/plain; charset="UTF-8"
...
--00000000000041bd3405c3403048
Content-Type: image/png; name="download.png"
Content-Disposition: attachment; filename="download.png"
...
TAG10 OK FETCH completed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see in this code that some blocks are delimited by hex numbers between -- --, called parts. A message with parts is called a multipart message. It’s possible to get such parts directly by passing the part index to the command.&lt;/p&gt;

&lt;p&gt;In order to delete messages, the protocol has the commands STORE and EXPUNGE, which mark a message as deleted and commit such an operation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TAG11 STORE 1 +FLAGS (\Deleted)
* 0 EXISTS
* 0 RECENT
TAG11 OK [READ-WRITE] SELECT completed; now in selected state
TAG12 EXPUNGE
EXPUNGE: TAG12 OK EXPUNGE completed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last command is simple: NOOP. This command does nothing but is used to implement a keep-alive strategy. By default, the IMAP session closes after 30 minutes without commands. So, issuing the NOOP command keeps the connection active.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TAG17 NOOP
TAG17 OK NOOP completed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this finishes our IMAP overview. If you’d like more information, there are a lot of good articles on the Web (I've selected some in resources section), and of course always remember the &lt;a href="https://datatracker.ietf.org/doc/html/rfc3501"&gt;RFC 3501&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.atmail.com/blog/imap-101-manual-imap-sessions/"&gt;Atmail’s IMAP 101: Manual IMAP Sessions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fastmail.help/hc/en-us/articles/360060591353-Why-is-IMAP-better-than-POP-"&gt;Fastmail’s Why is IMAP better than POP?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc3501"&gt;IETF’s Internet Message Access Protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc2045"&gt;IETF’s Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nylas.com/blog/nylas-imap-therefore-i-am/"&gt;Nylas’ Everything you need to know about IMAP&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next part, you'll use those commands within IRIS and see them in action!&lt;/p&gt;

&lt;p&gt;See you! :)&lt;/p&gt;

</description>
      <category>interoperability</category>
      <category>imap</category>
      <category>intersystems</category>
    </item>
  </channel>
</rss>
