Renamed listAllMessagesWithEInvoice() to fetchAllEmails() and listenForNewReceivedEInvoices() to listenForNewEmails()

This commit is contained in:
dankito 2024-11-26 02:43:24 +01:00
parent d66afa50a9
commit 8b7bd31cf1
4 changed files with 33 additions and 25 deletions

View File

@ -24,12 +24,16 @@ val invoiceFromXml = reader.extractFromXml(File("XRechnung.xml"))
```kotlin ```kotlin
val emailsFetcher = EmailsFetcher() val emailsFetcher = EmailsFetcher()
val mailsWithEInvoices = emailsFetcher.listAllMessagesWithEInvoice(EmailAccount( val fetchResult = emailsFetcher.fetchAllEmails(EmailAccount(
username = "", // your mail account username username = "", // your email account username
password = "", // your mail account username password = "", // your email account username
serverAddress = "", // IMAP server address serverAddress = "", // IMAP server address
port = null // IMAP server port, can be left null for default port 993 port = null // IMAP server port, can be left null for default port 993
)) ))
fetchResult.emails.forEach { email ->
println("${email.sender}: ${email.attachmentsWithEInvoice.firstNotNullOfOrNull { it.invoice }?.totalAmounts?.duePayableAmount}")
}
``` ```
### Validate eInvoice ### Validate eInvoice

View File

@ -29,13 +29,13 @@ open class EmailsFetcher(
) )
protected open val mailDispatcher = Executors.newFixedThreadPool(max(24, Runtime.getRuntime().availableProcessors() * 4)).asCoroutineDispatcher() protected open val coroutineDispatcher = Executors.newFixedThreadPool(max(24, Runtime.getRuntime().availableProcessors() * 4)).asCoroutineDispatcher()
protected val log by logger() protected val log by logger()
open fun listenForNewReceivedEInvoices(account: EmailAccount, downloadMessageBody: Boolean = false, emailFolderName: String = "INBOX", open fun listenForNewEmails(account: EmailAccount, downloadMessageBody: Boolean = false, emailFolderName: String = "INBOX",
error: ((FetchEmailsError) -> Unit)? = null, eInvoiceReceived: (EmailWithInvoice) -> Unit) = runBlocking { error: ((FetchEmailsError) -> Unit)? = null, emailReceived: (EmailWithInvoice) -> Unit) = runBlocking {
try { try {
connect(account) { store -> connect(account) { store ->
val folder = store.getFolder(emailFolderName) val folder = store.getFolder(emailFolderName)
@ -47,26 +47,26 @@ open class EmailsFetcher(
override fun messagesAdded(event: MessageCountEvent) { override fun messagesAdded(event: MessageCountEvent) {
event.messages.forEach { message -> event.messages.forEach { message ->
findEInvoice(message, status)?.let { findEInvoice(message, status)?.let {
eInvoiceReceived(it) emailReceived(it)
} }
} }
} }
}) })
launch(mailDispatcher) { launch(coroutineDispatcher) {
keepConnectionOpen(account, folder) keepConnectionOpen(account, folder)
} }
} }
} catch (e: Throwable) { } catch (e: Throwable) {
log.error(e) { "Listening to new received eInvoices of '${account.username}' failed" } log.error(e) { "Listening to new emails of '${account.username}' failed" }
error?.invoke(FetchEmailsError(FetchEmailsErrorType.ListenForNewEmails, null, e)) error?.invoke(FetchEmailsError(FetchEmailsErrorType.ListenForNewEmails, null, e))
} }
log.info { "Stopped listening to new received eInvoices of '${account.username}'" } log.info { "Stopped listening to new emails of '${account.username}'" }
} }
protected open suspend fun keepConnectionOpen(account: EmailAccount, folder: Folder) { protected open suspend fun keepConnectionOpen(account: EmailAccount, folder: Folder) {
log.info { "Listening to new mails of ${account.username}" } log.info { "Listening to new emails of ${account.username}" }
// Use IMAP IDLE to keep the connection alive // Use IMAP IDLE to keep the connection alive
while (true) { while (true) {
@ -82,7 +82,7 @@ open class EmailsFetcher(
} }
open fun listAllMessagesWithEInvoice(account: EmailAccount, downloadMessageBody: Boolean = false, emailFolderName: String = "INBOX"): FetchEmailsResult { open fun fetchAllEmails(account: EmailAccount, downloadMessageBody: Boolean = false, emailFolderName: String = "INBOX"): FetchEmailsResult {
try { try {
return connect(account) { store -> return connect(account) { store ->
val inbox = store.getFolder(emailFolderName) val inbox = store.getFolder(emailFolderName)
@ -90,31 +90,31 @@ open class EmailsFetcher(
val status = FetchEmailsStatus(FetchEmailsOptions(downloadMessageBody)) val status = FetchEmailsStatus(FetchEmailsOptions(downloadMessageBody))
val mails = listAllMessagesWithEInvoiceInFolder(inbox, status).also { val emails = fetchAllEmailsInFolder(inbox, status).also {
inbox.close(false) inbox.close(false)
} }
FetchEmailsResult(mails, null, status.messageSpecificErrors) FetchEmailsResult(emails, null, status.messageSpecificErrors)
} }
} catch (e: Throwable) { } catch (e: Throwable) {
log.error(e) { "Could not read mails of account $account" } log.error(e) { "Could not fetch emails of account $account" }
return FetchEmailsResult(emptyList(), e) return FetchEmailsResult(emptyList(), e)
} }
} }
protected open fun listAllMessagesWithEInvoiceInFolder(folder: Folder, status: FetchEmailsStatus): List<EmailWithInvoice> = runBlocking { protected open fun fetchAllEmailsInFolder(folder: Folder, status: FetchEmailsStatus): List<EmailWithInvoice> = runBlocking {
val messageCount = folder.messageCount val messageCount = folder.messageCount
if (messageCount <= 0) { if (messageCount <= 0) {
return@runBlocking emptyList() return@runBlocking emptyList()
} }
IntRange(1, messageCount).mapNotNull { messageNumber -> // message numbers start at 1 IntRange(1, messageCount).mapNotNull { messageNumber -> // message numbers start at 1
async(mailDispatcher) { async(coroutineDispatcher) {
try { try {
findEInvoice(folder.getMessage(messageNumber), status) findEInvoice(folder.getMessage(messageNumber), status)
} catch (e: Throwable) { } catch (e: Throwable) {
log.error(e) { "Could not get message with messageNumber $messageNumber" } log.error(e) { "Could not get email with messageNumber $messageNumber" }
status.addError(FetchEmailsErrorType.GetEmail, messageNumber, e) status.addError(FetchEmailsErrorType.GetEmail, messageNumber, e)
null null
} }

View File

@ -27,12 +27,16 @@ class Demonstration {
fun fromEmail() { fun fromEmail() {
val emailsFetcher = EmailsFetcher() val emailsFetcher = EmailsFetcher()
val mailsWithEInvoices = emailsFetcher.listAllMessagesWithEInvoice(EmailAccount( val fetchResult = emailsFetcher.fetchAllEmails(EmailAccount(
username = "", // your mail account username username = "", // your email account username
password = "", // your mail account username password = "", // your email account username
serverAddress = "", // IMAP server address serverAddress = "", // IMAP server address
port = null // IMAP server port, can be left null for default port 993 port = null // IMAP server port, can be left null for default port 993
)) ))
fetchResult.emails.forEach { email ->
println("${email.sender}: ${email.attachmentsWithEInvoice.firstNotNullOfOrNull { it.invoice }?.totalAmounts?.duePayableAmount}")
}
} }
fun validate() { fun validate() {

View File

@ -6,11 +6,11 @@ import assertk.assertions.isNotEmpty
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import kotlin.test.Ignore import kotlin.test.Ignore
@Ignore // not an automatic test, set your mail account settings below @Ignore // not an automatic test, set your email account settings below
class EmailsFetcherTest { class EmailsFetcherTest {
companion object { companion object {
// specify your mail account here // specify your email account here
private val emailAccount = EmailAccount( private val emailAccount = EmailAccount(
username = "", username = "",
password = "", password = "",
@ -24,8 +24,8 @@ class EmailsFetcherTest {
@Test @Test
fun listAllMessagesWithEInvoice() { fun fetchAllEmails() {
val result = underTest.listAllMessagesWithEInvoice(emailAccount, true) val result = underTest.fetchAllEmails(emailAccount, true)
assertThat(result.emails).isNotEmpty() assertThat(result.emails).isNotEmpty()