Returning now all mails and attachments, not only those with eInvoices

This commit is contained in:
dankito 2024-11-26 03:47:55 +01:00
parent c3cf0652b2
commit d70a748ad0
8 changed files with 34 additions and 38 deletions

View File

@ -32,7 +32,7 @@ val fetchResult = emailsFetcher.fetchAllEmails(EmailAccount(
))
fetchResult.emails.forEach { email ->
println("${email.sender}: ${email.attachmentsWithEInvoice.firstNotNullOfOrNull { it.invoice }?.totalAmounts?.duePayableAmount}")
println("${email.sender}: ${email.attachments.firstNotNullOfOrNull { it.invoice }?.totalAmounts?.duePayableAmount}")
}
```

View File

@ -10,8 +10,8 @@ import jakarta.mail.event.MessageCountAdapter
import jakarta.mail.event.MessageCountEvent
import kotlinx.coroutines.*
import net.codinux.invoicing.email.model.EmailAccount
import net.codinux.invoicing.email.model.EmailAttachmentWithEInvoice
import net.codinux.invoicing.email.model.EmailWithInvoice
import net.codinux.invoicing.email.model.EmailAttachment
import net.codinux.invoicing.email.model.Email
import net.codinux.invoicing.model.Invoice
import net.codinux.invoicing.reader.EInvoiceReader
import net.codinux.log.logger
@ -47,7 +47,7 @@ open class EmailsFetcher(
folder.addMessageCountListener(object : MessageCountAdapter() {
override fun messagesAdded(event: MessageCountEvent) {
event.messages.forEach { message ->
findEInvoice(message, status)
getEmail(message, status)
}
}
})
@ -102,7 +102,7 @@ open class EmailsFetcher(
}
}
protected open fun fetchAllEmailsInFolder(folder: Folder, status: FetchEmailsStatus): List<EmailWithInvoice> = runBlocking {
protected open fun fetchAllEmailsInFolder(folder: Folder, status: FetchEmailsStatus): List<Email> = runBlocking {
val messageCount = folder.messageCount
if (messageCount <= 0) {
return@runBlocking emptyList()
@ -111,7 +111,7 @@ open class EmailsFetcher(
IntRange(1, messageCount).mapNotNull { messageNumber -> // message numbers start at 1
async(coroutineDispatcher) {
try {
findEInvoice(folder.getMessage(messageNumber), status)
getEmail(folder.getMessage(messageNumber), status)
} catch (e: Throwable) {
log.error(e) { "Could not get email with messageNumber $messageNumber" }
status.addError(FetchEmailsErrorType.GetEmail, messageNumber, e)
@ -123,43 +123,39 @@ open class EmailsFetcher(
.filterNotNull()
}
protected open fun findEInvoice(message: Message, status: FetchEmailsStatus): EmailWithInvoice? {
protected open fun getEmail(message: Message, status: FetchEmailsStatus): Email? {
val parts = getAllMessageParts(message)
val attachmentsWithEInvoice = parts.mapNotNull { part ->
findEInvoice(part, status)
val attachments = parts.mapNotNull { part ->
findAttachment(part, status)
}
if (attachmentsWithEInvoice.isNotEmpty()) {
val email = EmailWithInvoice(
message.from?.joinToString(), message.subject ?: "",
message.sentDate?.let { map(it) }, map(message.receivedDate), message.messageNumber,
parts.any { it.mediaType == "application/pgp-encrypted" },
getPlainTextBody(parts, status), getHtmlBody(parts, status),
attachmentsWithEInvoice
)
val email = Email(
message.from?.joinToString(), message.subject ?: "",
message.sentDate?.let { map(it) }, map(message.receivedDate), message.messageNumber,
parts.any { it.mediaType == "application/pgp-encrypted" },
getPlainTextBody(parts, status), getHtmlBody(parts, status),
attachments
)
status.options.emailReceived(email)
status.options.emailReceived(email)
return email
}
return null
return email
}
protected open fun findEInvoice(messagePart: MessagePart, status: FetchEmailsStatus): EmailAttachmentWithEInvoice? {
protected open fun findAttachment(messagePart: MessagePart, status: FetchEmailsStatus): EmailAttachment? {
try {
val part = messagePart.part
val invoice = tryToReadEInvoice(part, messagePart.mediaType, status)
if (invoice != null) {
if (invoice != null || Part.ATTACHMENT.equals(part.description, ignoreCase = true)) {
val filename = File(part.fileName)
val file = File.createTempFile(filename.nameWithoutExtension, "." + filename.extension).also { file ->
part.inputStream.use { it.copyTo(file.outputStream()) }
file.deleteOnExit()
}
return EmailAttachmentWithEInvoice(part.fileName, messagePart.mediaType, invoice, file)
return EmailAttachment(part.fileName, messagePart.mediaType, invoice, file)
}
} catch (e: Throwable) {
log.error(e) { "Could not check attachment '${messagePart.part.fileName}' (${messagePart.mediaType}) for eInvoice" }

View File

@ -1,15 +1,15 @@
package net.codinux.invoicing.email
import net.codinux.invoicing.email.model.EmailWithInvoice
import net.codinux.invoicing.email.model.Email
open class FetchEmailsOptions(
val downloadMessageBody: Boolean = false,
val emailFolderName: String = "INBOX",
val onError: ((FetchEmailsError) -> Unit)? = null,
val onEmailReceived: ((EmailWithInvoice) -> Unit)? = null
val onEmailReceived: ((Email) -> Unit)? = null
) {
fun emailReceived(email: EmailWithInvoice) {
fun emailReceived(email: Email) {
onEmailReceived?.invoke(email)
}
}

View File

@ -1,9 +1,9 @@
package net.codinux.invoicing.email
import net.codinux.invoicing.email.model.EmailWithInvoice
import net.codinux.invoicing.email.model.Email
data class FetchEmailsResult(
val emails: List<EmailWithInvoice>,
val emails: List<Email>,
val overallError: Throwable?,
val messageSpecificErrors: List<FetchEmailsError> = emptyList()
)

View File

@ -1,6 +1,6 @@
package net.codinux.invoicing.email
import net.codinux.invoicing.email.model.EmailWithInvoice
import net.codinux.invoicing.email.model.Email
import java.util.concurrent.atomic.AtomicBoolean
open class ListenForNewMailsOptions(
@ -10,5 +10,5 @@ open class ListenForNewMailsOptions(
emailFolderName: String = "INBOX",
onError: ((FetchEmailsError) -> Unit)? = null,
onEmailReceived: (EmailWithInvoice) -> Unit
onEmailReceived: (Email) -> Unit
) : FetchEmailsOptions(downloadMessageBody, emailFolderName, onError, onEmailReceived)

View File

@ -3,7 +3,7 @@ package net.codinux.invoicing.email.model
import java.time.Instant
import java.time.ZoneId
class EmailWithInvoice(
class Email(
val sender: String?,
val subject: String,
val sent: Instant?,
@ -19,9 +19,9 @@ class EmailWithInvoice(
val isEncrypted: Boolean = false,
val plainTextBody: String?,
val htmlBody: String?,
val attachmentsWithEInvoice: List<EmailAttachmentWithEInvoice>
val attachments: List<EmailAttachment>
) {
val plainTextOrHtmlBody: String? by lazy { plainTextBody ?: htmlBody }
override fun toString() = "${(sent ?: received).atZone(ZoneId.systemDefault()).toLocalDate()} $sender: $subject, ${attachmentsWithEInvoice.size} invoice(s)"
override fun toString() = "${(sent ?: received).atZone(ZoneId.systemDefault()).toLocalDate()} $sender: $subject, ${attachments.size} attachment(s)"
}

View File

@ -3,7 +3,7 @@ package net.codinux.invoicing.email.model
import net.codinux.invoicing.model.Invoice
import java.io.File
class EmailAttachmentWithEInvoice(
class EmailAttachment(
val filename: String,
/**
* Attachment's media type like "application/xml", "application/pdf", ...
@ -11,7 +11,7 @@ class EmailAttachmentWithEInvoice(
* Should always be non-null, but can theoretically be null.
*/
val mediaType: String?,
val invoice: Invoice,
val invoice: Invoice?,
val file: File
) {
override fun toString() = "$filename: $invoice"

View File

@ -35,7 +35,7 @@ class Demonstration {
))
fetchResult.emails.forEach { email ->
println("${email.sender}: ${email.attachmentsWithEInvoice.firstNotNullOfOrNull { it.invoice }?.totalAmounts?.duePayableAmount}")
println("${email.sender}: ${email.attachments.firstNotNullOfOrNull { it.invoice }?.totalAmounts?.duePayableAmount}")
}
}