diff --git a/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/email/EmailsFetcher.kt b/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/email/EmailsFetcher.kt index 1b102e7..92c1620 100644 --- a/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/email/EmailsFetcher.kt +++ b/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/email/EmailsFetcher.kt @@ -3,10 +3,13 @@ package net.codinux.invoicing.email import jakarta.mail.* import jakarta.mail.event.MessageCountAdapter import jakarta.mail.event.MessageCountEvent +import jakarta.mail.internet.InternetAddress +import jakarta.mail.internet.MimeUtility import kotlinx.coroutines.* -import net.codinux.invoicing.email.model.EmailAccount -import net.codinux.invoicing.email.model.EmailAttachment import net.codinux.invoicing.email.model.Email +import net.codinux.invoicing.email.model.EmailAccount +import net.codinux.invoicing.email.model.EmailAddress +import net.codinux.invoicing.email.model.EmailAttachment import net.codinux.invoicing.filesystem.FileUtil import net.codinux.invoicing.model.Invoice import net.codinux.invoicing.reader.EInvoiceReader @@ -151,9 +154,13 @@ open class EmailsFetcher( getAttachment(part, status) } + val sender = message.from?.firstOrNull()?.let { map(it) } + val email = Email( - message.from?.joinToString(), message.subject ?: "", - message.sentDate?.let { map(it) }, map(message.receivedDate), status.folder.getUID(message), + sender, message.subject ?: "", + message.getRecipients(Message.RecipientType.TO).map { map(it) }, message.getRecipients(Message.RecipientType.CC).map { map(it) }, + (message.replyTo.firstOrNull() as? InternetAddress)?.let { if (it.address != sender?.address) map(it) else null }, // only set replyTo if it differs from sender + map(message.sentDate ?: message.receivedDate), status.folder.getUID(message), parts.any { it.mediaType == "application/pgp-encrypted" }, getPlainTextBody(messageBodyParts, status), getHtmlBody(messageBodyParts, status), attachments @@ -164,6 +171,13 @@ open class EmailsFetcher( return email } + protected open fun map(address: Address): EmailAddress = + if (address is InternetAddress) { // use MimeUtility to parse e.g. Quoted-printable names that e.g. start with "=?UTF-8?Q?" + EmailAddress(address.address, address.personal?.let { MimeUtility.decodeText(it) }) + } else { + EmailAddress(address.toString()) + } + protected open fun getAttachment(messagePart: MessagePart, status: FetchEmailsStatus): EmailAttachment? { try { val part = messagePart.part diff --git a/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/email/model/Email.kt b/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/email/model/Email.kt index 420fba2..c37e84b 100644 --- a/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/email/model/Email.kt +++ b/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/email/model/Email.kt @@ -4,10 +4,12 @@ import java.time.Instant import java.time.ZoneId class Email( - val sender: String?, + val sender: EmailAddress?, val subject: String, - val sent: Instant?, - val received: Instant, + val to: List, + val cc: List, + val replayTo: EmailAddress?, + val date: Instant, val messageId: Long, val isEncrypted: Boolean = false, val plainTextBody: String?, @@ -16,5 +18,5 @@ class Email( ) { val plainTextOrHtmlBody: String? by lazy { plainTextBody ?: htmlBody } - override fun toString() = "${(sent ?: received).atZone(ZoneId.systemDefault()).toLocalDate()} $sender: $subject, ${attachments.size} attachment(s)" + override fun toString() = "${date.atZone(ZoneId.systemDefault()).toLocalDate()} $sender: $subject, ${attachments.size} attachment(s)" } \ No newline at end of file diff --git a/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/email/model/EmailAddress.kt b/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/email/model/EmailAddress.kt new file mode 100644 index 0000000..e978e38 --- /dev/null +++ b/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/email/model/EmailAddress.kt @@ -0,0 +1,16 @@ +package net.codinux.invoicing.email.model + +class EmailAddress( + /** + * The email address, like "a@b.com" + */ + val address: String, + /** + * Sender or recipient's name like "Mahatma Gandhi" + */ + val name: String? = null +) { + override fun toString() = + if (name == null) address + else "$name <$address>" +} \ No newline at end of file