connect() now opens folder and returns FetchEmailsStatus, added close()

This commit is contained in:
dankito 2024-11-30 20:54:32 +01:00
parent 52bf9daa7d
commit 1746346ceb
2 changed files with 36 additions and 29 deletions

View File

@ -42,13 +42,9 @@ open class EmailsFetcher(
open fun listenForNewEmails(account: EmailAccount, options: ListenForNewMailsOptions) = runBlocking { open fun listenForNewEmails(account: EmailAccount, options: ListenForNewMailsOptions) = runBlocking {
try { try {
connect(account, options) { store -> val status = connect(account, options)
val folder = store.getFolder(options.emailFolderName) as IMAPFolder
folder.open(Folder.READ_ONLY)
val status = FetchEmailsStatus(account, folder, options) status.folder.addMessageCountListener(object : MessageCountAdapter() {
folder.addMessageCountListener(object : MessageCountAdapter() {
override fun messagesAdded(event: MessageCountEvent) { override fun messagesAdded(event: MessageCountEvent) {
event.messages.forEach { message -> event.messages.forEach { message ->
getEmail(message, status) getEmail(message, status)
@ -57,17 +53,19 @@ open class EmailsFetcher(
}) })
launch(coroutineDispatcher) { launch(coroutineDispatcher) {
keepConnectionOpen(status, folder, options) keepConnectionOpen(status, options)
}
} }
close(status)
} catch (e: Throwable) { } catch (e: Throwable) {
log.error(e) { "Listening to new emails of '${account.username}' failed" } log.error(e) { "Listening to new emails of '${account.username}' failed" }
options.onError?.invoke(FetchEmailError(FetchEmailErrorType.ListenForNewEmails, null, e)) options.onError?.invoke(FetchEmailError(FetchEmailErrorType.ListenForNewEmails, null, e))
} }
} }
protected open suspend fun keepConnectionOpen(status: FetchEmailsStatus, folder: IMAPFolder, options: ListenForNewMailsOptions) { protected open suspend fun keepConnectionOpen(status: FetchEmailsStatus, options: ListenForNewMailsOptions) {
val account = status.account val account = status.account
val folder = status.folder
log.info { "Listening to new emails of $account" } log.info { "Listening to new emails of $account" }
// Use IMAP IDLE to keep the connection alive // Use IMAP IDLE to keep the connection alive
@ -88,18 +86,13 @@ open class EmailsFetcher(
open fun fetchAllEmails(account: EmailAccount, options: FetchEmailsOptions = FetchEmailsOptions()): FetchEmailsResult { open fun fetchAllEmails(account: EmailAccount, options: FetchEmailsOptions = FetchEmailsOptions()): FetchEmailsResult {
try { try {
return connect(account, options) { store -> val status = connect(account, options)
val folder = store.getFolder(options.emailFolderName) as IMAPFolder
folder.open(Folder.READ_ONLY)
val status = FetchEmailsStatus(account, folder, options) val emails = fetchAllEmailsInFolder(status)
val emails = fetchAllEmailsInFolder(status).also { close(status)
folder.close(false)
}
FetchEmailsResult(emails, null, status.messageSpecificErrors) return FetchEmailsResult(emails, null, status.messageSpecificErrors)
}
} catch (e: Throwable) { } catch (e: Throwable) {
log.error(e) { "Could not fetch emails of account $account" } log.error(e) { "Could not fetch emails of account $account" }
@ -326,15 +319,17 @@ open class EmailsFetcher(
date.toInstant() date.toInstant()
protected open fun <T> connect(account: EmailAccount, options: FetchEmailsOptions, connected: (Store) -> T): T { protected open fun connect(account: EmailAccount, options: FetchEmailsOptions): FetchEmailsStatus {
val properties = mapAccountToJavaMailProperties(account, options) val properties = mapAccountToJavaMailProperties(account, options)
val session = Session.getInstance(properties) val session = Session.getInstance(properties)
session.getStore("imap").use { store -> val store = session.getStore("imap")
store.connect(account.serverAddress, account.username, account.password) store.connect(account.serverAddress, account.username, account.password)
return connected(store) val folder = store.getFolder(options.emailFolderName) as IMAPFolder
} folder.open(Folder.READ_ONLY)
return FetchEmailsStatus(account, store, folder, options)
} }
protected open fun mapAccountToJavaMailProperties(account: EmailAccount, options: FetchEmailsOptions) = Properties().apply { protected open fun mapAccountToJavaMailProperties(account: EmailAccount, options: FetchEmailsOptions) = Properties().apply {
@ -354,4 +349,14 @@ open class EmailsFetcher(
put("mail.imap.partialfetch", "false") // Controls whether the IMAP partial-fetch capability should be used. Defaults to true. put("mail.imap.partialfetch", "false") // Controls whether the IMAP partial-fetch capability should be used. Defaults to true.
} }
protected open fun close(status: FetchEmailsStatus) {
try {
status.folder.close(false)
status.store.close()
} catch (e: Exception) {
log.error(e) { "Could not close folder or store" }
}
}
} }

View File

@ -3,6 +3,7 @@ package net.codinux.invoicing.email
import jakarta.mail.BodyPart import jakarta.mail.BodyPart
import jakarta.mail.Message import jakarta.mail.Message
import jakarta.mail.Part import jakarta.mail.Part
import jakarta.mail.Store
import net.codinux.invoicing.email.model.EmailAccount import net.codinux.invoicing.email.model.EmailAccount
import net.codinux.invoicing.filesystem.FileUtil import net.codinux.invoicing.filesystem.FileUtil
import org.eclipse.angus.mail.imap.IMAPFolder import org.eclipse.angus.mail.imap.IMAPFolder
@ -10,6 +11,7 @@ import java.io.File
data class FetchEmailsStatus( data class FetchEmailsStatus(
val account: EmailAccount, val account: EmailAccount,
val store: Store,
val folder: IMAPFolder, val folder: IMAPFolder,
val options: FetchEmailsOptions, val options: FetchEmailsOptions,
val messageSpecificErrors: MutableList<FetchEmailError> = mutableListOf() val messageSpecificErrors: MutableList<FetchEmailError> = mutableListOf()