-
Notifications
You must be signed in to change notification settings - Fork 0
IMAP
Providing you have the correct credentials, you can connect to a given IMAP mail server with the following function:
val session = Kourrier.imap(
hostname = "mail.server.com",
port = 993,
username = "[email protected]",
password = "1234",
// debugMode = false,
// enableSSL = true,
// properties = Properties()
)
Do note that debugMode
, enableSSL
and properties
are optional:
-
debugMode
defaults to false, and serves to enable the debug mode for the current session. -
enableSSL
defaults to true, and serves to enable a Secure Socket Layer connection to the session. -
properties
is aProperties
object containing the properties to be used to obtain aSession
instance.
An incorrect hostname will lead to a KourrierConnectException
.
Incorrect credentials will lead to a KourrierAuthenticationException
.
The function itself returns an opened session. You will need to close it manually when you're done with it. When it's closed, you can reopen it manually:
session.close()
session.open()
Note that if you try to close a session that is already closed, or open a folder that is already open,
you'll hit a KourrierSessionStateException
.
Alternatively, you can instead keep the connection information in a variable to pass it later as an argument of the function, like so:
val creds = KourrierConnectionInfo(
hostname = "mail.server.com",
port = 993,
username = "[email protected]",
password = "1234",
// debugMode = false,
// enableSSL = true,
)
Kourrier.imap(
connectionInfo = creds,
// properties = Properties()
)
Now that you're connected, you can open folders an manipulate them using a neat DSL (Domain Specific Language).
To open open a folder, you just need its name, and it's opening mode:
val session = Kourrier.imap(...)
var inbox: KourrierFolder? = null
session {
inbox = folder(
name = "INBOX",
mode = KourrierFolderMode.ReadOnly, // KourrierFolderMode.ReadWrite,
// listener = null,
// keepAlive = false
) {
/* do something inside the folder */
}
}
Several things to notice here:
- The opening mode is an enum value of
KourrierFolderMode
, and can either beReadOnly
orReadWrite
. -
listener
is an optional argument that sets the folder listener (defaults to null). We'll go over that later in the Folder listener section. - The function itself returns the opened folder. You will need to close it when you're done with it.
When it's closed, you can reopen it manually:
Note that if you try to close a folder that is already closed, or open a folder that is already open, you'll hit a
folder.close(expunge = false) // will expunge the folder when closed (defaults to false) folder.open(mode = KourrierFolderMode.ReadOnly)
KourrierFolderStateException
. -
keepAlive
is an optionalBoolean
that indicates if one wants this folder to be kept alive forever until closed explicitly (defaults to false).- Being kept alive implies that it will be listened to, therefore, if you don't give any listener, there's little to no point for it to be kept alive.
- Note that if the store/session is closed during that time, you might hit a
KevalSessionStateException
; the session cannot be closed implicitly by the server.
While inside a folder, you have access to a DSL and several properties of said folder:
session {
folder(...) { // `this` is a KourrierFolder
messageCount // is the amount of messages in the folder
unreadCount // is the amount of unread messages in the folder
newCount // is the amount of new messages in the folder
hasNewMessage // is true if the current folder contains at least one new message
folderType // KourrierFolderType, indicates the content type of the folder
prefetchBy(/* vararg FetchProfile.Item */) // sets the prefetch profile
this[0] // returns the first message of the folder, or null
this[0 until messageCount /*, prefetch = true */] // returns the list of message from index 0 to messageCount-1, with a prefetch
sortedBy { /* ... */ } // uses the sort engine to return a list of messages
search { /* ... */ } // uses the search engine to return a list of messages
}
}
There's a lot of things to go over here:
-
folderType
is aKourrierFolderType
enum value, that can beHoldsFolders
,HoldsMessages
orHoldsAll
. -
prefetchBy
receives one or severalFetchProfile.Item
(see JavaMail documentation) and combines them to set it as the next prefecth profile. - The
IntRange
version of the message getter has an optionalBoolean
prefetch
that defaults to true, and idicates whether the batch should be prefetched or not. - We'll go over the sort and search engines in the next sections.
The sort engine returns a list of messages ordered by the defined DSL. You have several sort options that you can even reverse:
import com.notkamui.kourrier.search.KourriersortTerm.*
session {
folder(...) {
sortedBy {
+From // by email of the sender
+To // by email of the recipient
+Subject // by the subject
+Arrival // by the arrival date
+Sent // by the send date
+CC // by email of the first CC recipient
+Size // by size
}
}
}
The sort terms are enum values of KourrierSortTerm
(thus you can static import them for readability).
These all order in the natural/increasing direction (alphanumerical order / natural date order), however, you can reverse
the direction of the order by replacing the unary plus (+
) by an exclamation point (!
).
For example, !Size
adds a sort term by decreasing size (instead of increasing).
The search engine returns a list of messages following the defined DSL (note that you can call the sort engine inside the search engine too !):
session {
folder(...) {
search {
markAsRead // defaults to false, can be set to true. Marks the search results as read
hasSortTerms // whether sort terms have been applied, or not
sortTerms // the list of sort terms that have been applied
sortedBy { /*...*/ } // uses the sort engine, does not return anything
+from("[email protected]") // search sender
+to("[email protected]") // search regular recipient
+cc("[email protected]") // search CC recipient
+bcc("[email protected]") // search BCC recipient
+subject("Foo Bar Baz") // search subject
+body("Hello world") // search mail body content
+header("My head") // search mail header content
+receivedOn(Date(...)) // search received on date
+receivedOnOrAfter(Date(...)) // search received on or after date
+receivedAfter(Date(...)) // search received after date
+receivedOnOrBefore(Date(...)) // search received on or before date
+receivedBefore(Date(...)) // search received before date
+receivedBetween(Date(...) .. Date(...)) // search received in date range
+sentOn(Date(...)) // search sent on date
+sentOnOrAfter(Date(...)) // search sent on or after date
+sentAfter(Date(...)) // search sent after date
+sentOnOrBefore(Date(...)) // search sent on or before date
+sentBefore(Date(...)) // search sent before date
+sentBetween(Date(...) .. Date(...)) // search sent in date range
+messageID(0) // search by message ID
+messageNumber(0) // search by message number
+sizeIs(0) // search with exact size
+sizeIsAtLeast(0) // search with size or larger
+sizeIsLargerThan(0) // search with larger size
+sizeIsAtMost(0) // search with size or smaller
+sizeIsSmallerThan(0) // search with smaller size
+sizeBetween(0..10) // search with size between range
+flags(KourrierFlags(...), true) // search with `KourrierFlags`. Boolean is is true if the search contains flags, false for exclusion.
+modifiedSince(0L) // search with modification sequence (Long value)
+older(0) // search messages older than the given time (in seconds)
+younger(0) // search messages younger than the given time (in seconds)
+(from("A") and to("B")) // search with two predicates that have to be true
+(from("A") or to("B")) // search with two predicates with at least one true
}
}
}
Note that the flags
term receives a built KourrierFlags
. You can build a set of flags with the constructor that receives a vararg KourrierFlag
, which is an enum value that can be Answered
, Deleted
, Draft
, Flagged
, Recent
, Seen
, or User
.
You can inverse any search term by replacing the unary plus (+
) with an exclamation point (!
).
For example !from("[email protected]")
will search all messages EXCEPT those from [email protected]
.
Once you fetched IMAP messages, you'll be presented with instances of KourrierIMAPMessage
. They contain several properties:
-
uid
, the UID of the message -
from
, the address of the sender -
headers
, a list ofKourrierMessageHeader
s (which themselves have aname
and avalue
) -
subject
, the actual subject of the message -
body
, the full body content of the message -
bodyParts
, the full body content separated by body parts in a list (convenient forMimeMessage
s that are multipart)
If you recall, when opening a folder, there is an optional listener
parameter.
It is of type KourrierFolderListener
, which is an interface composed of 4 methods (which all take a KourrierIMAPMessage
as a parameter):
-
onMessageReceived
that will be launched for each message received in the folder. -
onMessageRemoved
that will be launched for each message removed (as in, expunged. Do note that it is NOT synonymous to "deleted") -
onMessageFlagsChanged
that will be launched for each message which has its flags updated. -
onMessageEnvelopeChanged
that will be launched for each message which has its headers (but not body) changed.
A generic open class KourrierFolderAdapter
is also available.
For example:
val listener = object : KourrierFolderAdapter() {
override fun onMessageReceived(message: KourrierIMAPMessage) {
println(message.bodyParts[0])
}
}
session {
folder("INBOX", KourrierFolderMode.ReadWrite, listener)
}
This will print the first body part of each message received until the folder is closed.
Keep in mind that some mail servers require the folder to be open in ReadWrite mode for it to be listenable !