Renamed classes from 'ReadMails' to 'FetchEmails'
This commit is contained in:
parent
eb9b42fb97
commit
d66afa50a9
|
@ -22,9 +22,9 @@ val invoiceFromXml = reader.extractFromXml(File("XRechnung.xml"))
|
||||||
### Find all invoices of an IMAP email account
|
### Find all invoices of an IMAP email account
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
val mailReader = MailReader()
|
val emailsFetcher = EmailsFetcher()
|
||||||
|
|
||||||
val mailsWithEInvoices = mailReader.listAllMessagesWithEInvoice(MailAccount(
|
val mailsWithEInvoices = emailsFetcher.listAllMessagesWithEInvoice(EmailAccount(
|
||||||
username = "", // your mail account username
|
username = "", // your mail account username
|
||||||
password = "", // your mail account username
|
password = "", // your mail account username
|
||||||
serverAddress = "", // IMAP server address
|
serverAddress = "", // IMAP server address
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
package net.codinux.invoicing.mail
|
package net.codinux.invoicing.mail
|
||||||
|
|
||||||
class MailAccount(
|
class EmailAccount(
|
||||||
val username: String,
|
val username: String,
|
||||||
val password: String,
|
val password: String,
|
||||||
/**
|
/**
|
||||||
* For reading mails the IMAP server address, for sending mails the SMTP server address.
|
* For fetching emails the IMAP server address, for sending emails the SMTP server address.
|
||||||
*/
|
*/
|
||||||
val serverAddress: String,
|
val serverAddress: String,
|
||||||
/**
|
/**
|
||||||
* Even though not mandatory it's better to specify the port, otherwise default port is tried.
|
* Even though not mandatory it's better to specify the port, otherwise default port (993 for IMAP, 587 for SMTP) is used.
|
||||||
*/
|
*/
|
||||||
val port: Int? = null
|
val port: Int? = null
|
||||||
) {
|
) {
|
|
@ -3,7 +3,7 @@ package net.codinux.invoicing.mail
|
||||||
import net.codinux.invoicing.model.Invoice
|
import net.codinux.invoicing.model.Invoice
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class MailAttachmentWithEInvoice(
|
class EmailAttachmentWithEInvoice(
|
||||||
val filename: String,
|
val filename: String,
|
||||||
/**
|
/**
|
||||||
* Attachment's media type like "application/xml", "application/pdf", ...
|
* Attachment's media type like "application/xml", "application/pdf", ...
|
|
@ -3,7 +3,7 @@ package net.codinux.invoicing.mail
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
|
|
||||||
class MailWithInvoice(
|
class EmailWithInvoice(
|
||||||
val sender: String?,
|
val sender: String?,
|
||||||
val subject: String,
|
val subject: String,
|
||||||
val sent: Instant?,
|
val sent: Instant?,
|
||||||
|
@ -13,13 +13,13 @@ class MailWithInvoice(
|
||||||
* "Since message numbers can change within a session if the folder is expunged, clients are advised not to use
|
* "Since message numbers can change within a session if the folder is expunged, clients are advised not to use
|
||||||
* message numbers as references to messages."
|
* message numbers as references to messages."
|
||||||
*
|
*
|
||||||
* -> use with care. Message numbers are not valid / the same anymore after expunge.
|
* -> use with care. Message numbers are not valid / the same anymore after expunging.
|
||||||
*/
|
*/
|
||||||
val messageNumber: Int,
|
val messageNumber: Int,
|
||||||
val isEncrypted: Boolean = false,
|
val isEncrypted: Boolean = false,
|
||||||
val plainTextBody: String?,
|
val plainTextBody: String?,
|
||||||
val htmlBody: String?,
|
val htmlBody: String?,
|
||||||
val attachmentsWithEInvoice: List<MailAttachmentWithEInvoice>
|
val attachmentsWithEInvoice: List<EmailAttachmentWithEInvoice>
|
||||||
) {
|
) {
|
||||||
val plainTextOrHtmlBody: String? by lazy { plainTextBody ?: htmlBody }
|
val plainTextOrHtmlBody: String? by lazy { plainTextBody ?: htmlBody }
|
||||||
|
|
|
@ -19,7 +19,7 @@ import java.util.*
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
open class MailReader(
|
open class EmailsFetcher(
|
||||||
protected open val eInvoiceReader: EInvoiceReader = EInvoiceReader()
|
protected open val eInvoiceReader: EInvoiceReader = EInvoiceReader()
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@ -34,14 +34,14 @@ open class MailReader(
|
||||||
protected val log by logger()
|
protected val log by logger()
|
||||||
|
|
||||||
|
|
||||||
open fun listenForNewReceivedEInvoices(account: MailAccount, downloadMessageBody: Boolean = false, emailFolderName: String = "INBOX",
|
open fun listenForNewReceivedEInvoices(account: EmailAccount, downloadMessageBody: Boolean = false, emailFolderName: String = "INBOX",
|
||||||
error: ((ReadMailError) -> Unit)? = null, eInvoiceReceived: (MailWithInvoice) -> Unit) = runBlocking {
|
error: ((FetchEmailsError) -> Unit)? = null, eInvoiceReceived: (EmailWithInvoice) -> Unit) = runBlocking {
|
||||||
try {
|
try {
|
||||||
connect(account) { store ->
|
connect(account) { store ->
|
||||||
val folder = store.getFolder(emailFolderName)
|
val folder = store.getFolder(emailFolderName)
|
||||||
folder.open(Folder.READ_ONLY)
|
folder.open(Folder.READ_ONLY)
|
||||||
|
|
||||||
val status = ReadMailsStatus(ReadMailsOptions(downloadMessageBody))
|
val status = FetchEmailsStatus(FetchEmailsOptions(downloadMessageBody))
|
||||||
|
|
||||||
folder.addMessageCountListener(object : MessageCountAdapter() {
|
folder.addMessageCountListener(object : MessageCountAdapter() {
|
||||||
override fun messagesAdded(event: MessageCountEvent) {
|
override fun messagesAdded(event: MessageCountEvent) {
|
||||||
|
@ -59,13 +59,13 @@ open class MailReader(
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
log.error(e) { "Listening to new received eInvoices of '${account.username}' failed" }
|
log.error(e) { "Listening to new received eInvoices of '${account.username}' failed" }
|
||||||
error?.invoke(ReadMailError(ReadMailsErrorType.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 received eInvoices of '${account.username}'" }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open suspend fun keepConnectionOpen(account: MailAccount, 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 mails of ${account.username}" }
|
||||||
|
|
||||||
// Use IMAP IDLE to keep the connection alive
|
// Use IMAP IDLE to keep the connection alive
|
||||||
|
@ -82,28 +82,28 @@ open class MailReader(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun listAllMessagesWithEInvoice(account: MailAccount, downloadMessageBody: Boolean = false, emailFolderName: String = "INBOX"): ReadMailsResult {
|
open fun listAllMessagesWithEInvoice(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)
|
||||||
inbox.open(Folder.READ_ONLY)
|
inbox.open(Folder.READ_ONLY)
|
||||||
|
|
||||||
val status = ReadMailsStatus(ReadMailsOptions(downloadMessageBody))
|
val status = FetchEmailsStatus(FetchEmailsOptions(downloadMessageBody))
|
||||||
|
|
||||||
val mails = listAllMessagesWithEInvoiceInFolder(inbox, status).also {
|
val mails = listAllMessagesWithEInvoiceInFolder(inbox, status).also {
|
||||||
inbox.close(false)
|
inbox.close(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadMailsResult(mails, null, status.mailSpecificErrors)
|
FetchEmailsResult(mails, null, status.messageSpecificErrors)
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
log.error(e) { "Could not read mails of account $account" }
|
log.error(e) { "Could not read mails of account $account" }
|
||||||
|
|
||||||
return ReadMailsResult(emptyList(), e)
|
return FetchEmailsResult(emptyList(), e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun listAllMessagesWithEInvoiceInFolder(folder: Folder, status: ReadMailsStatus): List<MailWithInvoice> = runBlocking {
|
protected open fun listAllMessagesWithEInvoiceInFolder(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()
|
||||||
|
@ -115,7 +115,7 @@ open class MailReader(
|
||||||
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 message with messageNumber $messageNumber" }
|
||||||
status.addError(ReadMailsErrorType.GetEmail, messageNumber, e)
|
status.addError(FetchEmailsErrorType.GetEmail, messageNumber, e)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ open class MailReader(
|
||||||
.filterNotNull()
|
.filterNotNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun findEInvoice(message: Message, status: ReadMailsStatus): MailWithInvoice? {
|
protected open fun findEInvoice(message: Message, status: FetchEmailsStatus): EmailWithInvoice? {
|
||||||
val parts = getAllMessageParts(message)
|
val parts = getAllMessageParts(message)
|
||||||
|
|
||||||
val attachmentsWithEInvoice = parts.mapNotNull { part ->
|
val attachmentsWithEInvoice = parts.mapNotNull { part ->
|
||||||
|
@ -132,7 +132,7 @@ open class MailReader(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attachmentsWithEInvoice.isNotEmpty()) {
|
if (attachmentsWithEInvoice.isNotEmpty()) {
|
||||||
return MailWithInvoice(
|
return EmailWithInvoice(
|
||||||
message.from?.joinToString(), message.subject ?: "",
|
message.from?.joinToString(), message.subject ?: "",
|
||||||
message.sentDate?.let { map(it) }, map(message.receivedDate), message.messageNumber,
|
message.sentDate?.let { map(it) }, map(message.receivedDate), message.messageNumber,
|
||||||
parts.any { it.mediaType == "application/pgp-encrypted" },
|
parts.any { it.mediaType == "application/pgp-encrypted" },
|
||||||
|
@ -144,7 +144,7 @@ open class MailReader(
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun findEInvoice(messagePart: MessagePart, status: ReadMailsStatus): MailAttachmentWithEInvoice? {
|
protected open fun findEInvoice(messagePart: MessagePart, status: FetchEmailsStatus): EmailAttachmentWithEInvoice? {
|
||||||
try {
|
try {
|
||||||
val part = messagePart.part
|
val part = messagePart.part
|
||||||
val invoice = tryToReadEInvoice(part, messagePart.mediaType, status)
|
val invoice = tryToReadEInvoice(part, messagePart.mediaType, status)
|
||||||
|
@ -156,17 +156,17 @@ open class MailReader(
|
||||||
file.deleteOnExit()
|
file.deleteOnExit()
|
||||||
}
|
}
|
||||||
|
|
||||||
return MailAttachmentWithEInvoice(part.fileName, messagePart.mediaType, invoice, file)
|
return EmailAttachmentWithEInvoice(part.fileName, messagePart.mediaType, invoice, file)
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
log.error(e) { "Could not check attachment '${messagePart.part.fileName}' (${messagePart.mediaType}) for eInvoice" }
|
log.error(e) { "Could not check attachment '${messagePart.part.fileName}' (${messagePart.mediaType}) for eInvoice" }
|
||||||
status.addError(ReadMailsErrorType.GetAttachment, messagePart.part, e)
|
status.addError(FetchEmailsErrorType.GetAttachment, messagePart.part, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun tryToReadEInvoice(part: Part, mediaType: String?, status: ReadMailsStatus): Invoice? = try {
|
protected open fun tryToReadEInvoice(part: Part, mediaType: String?, status: FetchEmailsStatus): Invoice? = try {
|
||||||
val filename = part.fileName?.lowercase() ?: ""
|
val filename = part.fileName?.lowercase() ?: ""
|
||||||
|
|
||||||
if (filename.endsWith(".pdf") || mediaType == "application/pdf" || mediaType == "application/octet-stream") {
|
if (filename.endsWith(".pdf") || mediaType == "application/pdf" || mediaType == "application/octet-stream") {
|
||||||
|
@ -178,7 +178,7 @@ open class MailReader(
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
log.debug(e) { "Could not extract invoices from ${part.fileName}" }
|
log.debug(e) { "Could not extract invoices from ${part.fileName}" }
|
||||||
status.addError(ReadMailsErrorType.ExtractInvoice, part, e)
|
status.addError(FetchEmailsErrorType.ExtractInvoice, part, e)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,13 +219,13 @@ open class MailReader(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun getPlainTextBody(parts: Collection<MessagePart>, status: ReadMailsStatus) =
|
protected open fun getPlainTextBody(parts: Collection<MessagePart>, status: FetchEmailsStatus) =
|
||||||
if (status.options.downloadMessageBody) getBodyWithMediaType(parts, "text/plain", status) else null
|
if (status.options.downloadMessageBody) getBodyWithMediaType(parts, "text/plain", status) else null
|
||||||
|
|
||||||
protected open fun getHtmlBody(parts: Collection<MessagePart>, status: ReadMailsStatus) =
|
protected open fun getHtmlBody(parts: Collection<MessagePart>, status: FetchEmailsStatus) =
|
||||||
if (status.options.downloadMessageBody) getBodyWithMediaType(parts, "text/html", status) else null
|
if (status.options.downloadMessageBody) getBodyWithMediaType(parts, "text/html", status) else null
|
||||||
|
|
||||||
protected open fun getBodyWithMediaType(parts: Collection<MessagePart>, mediaType: String, status: ReadMailsStatus): String? = try {
|
protected open fun getBodyWithMediaType(parts: Collection<MessagePart>, mediaType: String, status: FetchEmailsStatus): String? = try {
|
||||||
val partsForMediaType = parts.filter { it.mediaType == mediaType }
|
val partsForMediaType = parts.filter { it.mediaType == mediaType }
|
||||||
|
|
||||||
if (partsForMediaType.size == 1) {
|
if (partsForMediaType.size == 1) {
|
||||||
|
@ -245,7 +245,7 @@ open class MailReader(
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
log.error(e) { "Could not get message body for media type '$mediaType'" }
|
log.error(e) { "Could not get message body for media type '$mediaType'" }
|
||||||
status.addError(ReadMailsErrorType.GetMesssageBody, parts.map { it.part }, e)
|
status.addError(FetchEmailsErrorType.GetMesssageBody, parts.map { it.part }, e)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@ open class MailReader(
|
||||||
date.toInstant()
|
date.toInstant()
|
||||||
|
|
||||||
|
|
||||||
protected open fun <T> connect(account: MailAccount, connected: (Store) -> T): T {
|
protected open fun <T> connect(account: EmailAccount, connected: (Store) -> T): T {
|
||||||
val properties = mapAccountToJavaMailProperties(account)
|
val properties = mapAccountToJavaMailProperties(account)
|
||||||
|
|
||||||
val session = Session.getInstance(properties)
|
val session = Session.getInstance(properties)
|
||||||
|
@ -264,7 +264,7 @@ open class MailReader(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun mapAccountToJavaMailProperties(account: MailAccount) = Properties().apply {
|
protected open fun mapAccountToJavaMailProperties(account: EmailAccount) = Properties().apply {
|
||||||
put("mail.store.protocol", "imap")
|
put("mail.store.protocol", "imap")
|
||||||
|
|
||||||
put("mail.imap.host", account.serverAddress)
|
put("mail.imap.host", account.serverAddress)
|
|
@ -1,7 +1,7 @@
|
||||||
package net.codinux.invoicing.mail
|
package net.codinux.invoicing.mail
|
||||||
|
|
||||||
data class ReadMailError(
|
data class FetchEmailsError(
|
||||||
val type: ReadMailsErrorType,
|
val type: FetchEmailsErrorType,
|
||||||
val messageNumber: Int?,
|
val messageNumber: Int?,
|
||||||
val error: Throwable
|
val error: Throwable
|
||||||
)
|
)
|
|
@ -1,6 +1,6 @@
|
||||||
package net.codinux.invoicing.mail
|
package net.codinux.invoicing.mail
|
||||||
|
|
||||||
enum class ReadMailsErrorType {
|
enum class FetchEmailsErrorType {
|
||||||
GetEmail,
|
GetEmail,
|
||||||
|
|
||||||
GetMesssageBody,
|
GetMesssageBody,
|
|
@ -1,5 +1,5 @@
|
||||||
package net.codinux.invoicing.mail
|
package net.codinux.invoicing.mail
|
||||||
|
|
||||||
data class ReadMailsOptions(
|
data class FetchEmailsOptions(
|
||||||
val downloadMessageBody: Boolean = false
|
val downloadMessageBody: Boolean = false
|
||||||
)
|
)
|
|
@ -0,0 +1,7 @@
|
||||||
|
package net.codinux.invoicing.mail
|
||||||
|
|
||||||
|
data class FetchEmailsResult(
|
||||||
|
val emails: List<EmailWithInvoice>,
|
||||||
|
val overallError: Throwable?,
|
||||||
|
val messageSpecificErrors: List<FetchEmailsError> = emptyList()
|
||||||
|
)
|
|
@ -0,0 +1,39 @@
|
||||||
|
package net.codinux.invoicing.mail
|
||||||
|
|
||||||
|
import jakarta.mail.BodyPart
|
||||||
|
import jakarta.mail.Message
|
||||||
|
import jakarta.mail.Part
|
||||||
|
|
||||||
|
data class FetchEmailsStatus(
|
||||||
|
val options: FetchEmailsOptions,
|
||||||
|
val messageSpecificErrors: MutableList<FetchEmailsError> = mutableListOf(),
|
||||||
|
val error: ((FetchEmailsError) -> Unit)? = null
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun addError(type: FetchEmailsErrorType, parts: Collection<Part>, error: Throwable) =
|
||||||
|
addError(FetchEmailsError(type, parts.firstNotNullOfOrNull { getMessage(it) }?.messageNumber, error))
|
||||||
|
|
||||||
|
fun addError(type: FetchEmailsErrorType, part: Part, error: Throwable) =
|
||||||
|
addError(FetchEmailsError(type, getMessage(part)?.messageNumber, error))
|
||||||
|
|
||||||
|
fun addError(type: FetchEmailsErrorType, messageNumber: Int?, error: Throwable) =
|
||||||
|
addError(FetchEmailsError(type, messageNumber, error))
|
||||||
|
|
||||||
|
fun addError(mailError: FetchEmailsError) {
|
||||||
|
messageSpecificErrors.add(mailError)
|
||||||
|
|
||||||
|
error?.invoke(mailError)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getMessage(part: Part): Message? {
|
||||||
|
if (part is Message) {
|
||||||
|
return part
|
||||||
|
}
|
||||||
|
|
||||||
|
(part as? BodyPart)?.parent.let { parent ->
|
||||||
|
return getMessage(part)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +0,0 @@
|
||||||
package net.codinux.invoicing.mail
|
|
||||||
|
|
||||||
data class ReadMailsResult(
|
|
||||||
val emails: List<MailWithInvoice>,
|
|
||||||
val overallError: Throwable?,
|
|
||||||
val messageSpecificErrors: List<ReadMailError> = emptyList()
|
|
||||||
)
|
|
|
@ -1,39 +0,0 @@
|
||||||
package net.codinux.invoicing.mail
|
|
||||||
|
|
||||||
import jakarta.mail.BodyPart
|
|
||||||
import jakarta.mail.Message
|
|
||||||
import jakarta.mail.Part
|
|
||||||
|
|
||||||
data class ReadMailsStatus(
|
|
||||||
val options: ReadMailsOptions,
|
|
||||||
val mailSpecificErrors: MutableList<ReadMailError> = mutableListOf(),
|
|
||||||
val error: ((ReadMailError) -> Unit)? = null
|
|
||||||
) {
|
|
||||||
|
|
||||||
fun addError(type: ReadMailsErrorType, parts: Collection<Part>, error: Throwable) =
|
|
||||||
addError(ReadMailError(type, parts.firstNotNullOfOrNull { getMessage(it) }?.messageNumber, error))
|
|
||||||
|
|
||||||
fun addError(type: ReadMailsErrorType, part: Part, error: Throwable) =
|
|
||||||
addError(ReadMailError(type, getMessage(part)?.messageNumber, error))
|
|
||||||
|
|
||||||
fun addError(type: ReadMailsErrorType, messageNumber: Int?, error: Throwable) =
|
|
||||||
addError(ReadMailError(type, messageNumber, error))
|
|
||||||
|
|
||||||
fun addError(mailError: ReadMailError) {
|
|
||||||
mailSpecificErrors.add(mailError)
|
|
||||||
|
|
||||||
error?.invoke(mailError)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getMessage(part: Part): Message? {
|
|
||||||
if (part is Message) {
|
|
||||||
return part
|
|
||||||
}
|
|
||||||
|
|
||||||
(part as? BodyPart)?.parent.let { parent ->
|
|
||||||
return getMessage(part)
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +1,8 @@
|
||||||
package net.codinux.invoicing
|
package net.codinux.invoicing
|
||||||
|
|
||||||
import net.codinux.invoicing.creation.EInvoiceCreator
|
import net.codinux.invoicing.creation.EInvoiceCreator
|
||||||
import net.codinux.invoicing.mail.MailAccount
|
import net.codinux.invoicing.mail.EmailAccount
|
||||||
import net.codinux.invoicing.mail.MailReader
|
import net.codinux.invoicing.mail.EmailsFetcher
|
||||||
import net.codinux.invoicing.model.Invoice
|
import net.codinux.invoicing.model.Invoice
|
||||||
import net.codinux.invoicing.model.InvoiceItem
|
import net.codinux.invoicing.model.InvoiceItem
|
||||||
import net.codinux.invoicing.model.Party
|
import net.codinux.invoicing.model.Party
|
||||||
|
@ -24,10 +24,10 @@ class Demonstration {
|
||||||
val invoiceFromXml = reader.extractFromXml(File("XRechnung.xml"))
|
val invoiceFromXml = reader.extractFromXml(File("XRechnung.xml"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fromMail() {
|
fun fromEmail() {
|
||||||
val mailReader = MailReader()
|
val emailsFetcher = EmailsFetcher()
|
||||||
|
|
||||||
val mailsWithEInvoices = mailReader.listAllMessagesWithEInvoice(MailAccount(
|
val mailsWithEInvoices = emailsFetcher.listAllMessagesWithEInvoice(EmailAccount(
|
||||||
username = "", // your mail account username
|
username = "", // your mail account username
|
||||||
password = "", // your mail account username
|
password = "", // your mail account username
|
||||||
serverAddress = "", // IMAP server address
|
serverAddress = "", // IMAP server address
|
||||||
|
|
|
@ -7,11 +7,11 @@ 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 mail account settings below
|
||||||
class MailReaderTest {
|
class EmailsFetcherTest {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// specify your mail account here
|
// specify your mail account here
|
||||||
private val mailAccount = MailAccount(
|
private val emailAccount = EmailAccount(
|
||||||
username = "",
|
username = "",
|
||||||
password = "",
|
password = "",
|
||||||
serverAddress = "",
|
serverAddress = "",
|
||||||
|
@ -20,12 +20,12 @@ class MailReaderTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private val underTest = MailReader()
|
private val underTest = EmailsFetcher()
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun listAllMessagesWithEInvoice() {
|
fun listAllMessagesWithEInvoice() {
|
||||||
val result = underTest.listAllMessagesWithEInvoice(mailAccount, true)
|
val result = underTest.listAllMessagesWithEInvoice(emailAccount, true)
|
||||||
|
|
||||||
assertThat(result.emails).isNotEmpty()
|
assertThat(result.emails).isNotEmpty()
|
||||||
|
|
Loading…
Reference in New Issue