Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-24 18:55:42 +01:00
parent a629de6271
commit 3cef7c5092
2161 changed files with 246605 additions and 2 deletions

View file

@ -0,0 +1,9 @@
@Suppress("DSL_SCOPE_VIOLATION")
plugins {
id(ThunderbirdPlugins.Library.jvm)
alias(libs.plugins.android.lint)
}
dependencies {
api(projects.mail.common)
}

View file

@ -0,0 +1,19 @@
package com.fsck.k9.autodiscovery.api
import com.fsck.k9.mail.AuthType
import com.fsck.k9.mail.ConnectionSecurity
interface ConnectionSettingsDiscovery {
fun discover(email: String): DiscoveryResults?
}
data class DiscoveryResults(val incoming: List<DiscoveredServerSettings>, val outgoing: List<DiscoveredServerSettings>)
data class DiscoveredServerSettings(
val protocol: String,
val host: String,
val port: Int,
val security: ConnectionSecurity,
val authType: AuthType?,
val username: String?
)

View file

@ -0,0 +1,20 @@
plugins {
id(ThunderbirdPlugins.Library.android)
}
dependencies {
implementation(projects.app.core)
implementation(projects.mail.common)
implementation(projects.app.autodiscovery.api)
implementation(libs.timber)
testImplementation(projects.app.testing)
testImplementation(projects.backend.imap)
testImplementation(libs.robolectric)
testImplementation(libs.androidx.test.core)
}
android {
namespace = "com.fsck.k9.autodiscovery.providersxml"
}

View file

@ -0,0 +1,8 @@
package com.fsck.k9.autodiscovery.providersxml
import org.koin.dsl.module
val autodiscoveryProvidersXmlModule = module {
factory { ProvidersXmlProvider(context = get()) }
factory { ProvidersXmlDiscovery(xmlProvider = get(), oAuthConfigurationProvider = get()) }
}

View file

@ -0,0 +1,156 @@
package com.fsck.k9.autodiscovery.providersxml
import android.content.res.XmlResourceParser
import android.net.Uri
import com.fsck.k9.autodiscovery.api.ConnectionSettingsDiscovery
import com.fsck.k9.autodiscovery.api.DiscoveredServerSettings
import com.fsck.k9.autodiscovery.api.DiscoveryResults
import com.fsck.k9.helper.EmailHelper
import com.fsck.k9.mail.AuthType
import com.fsck.k9.mail.ConnectionSecurity
import com.fsck.k9.oauth.OAuthConfigurationProvider
import com.fsck.k9.preferences.Protocols
import org.xmlpull.v1.XmlPullParser
import timber.log.Timber
class ProvidersXmlDiscovery(
private val xmlProvider: ProvidersXmlProvider,
private val oAuthConfigurationProvider: OAuthConfigurationProvider
) : ConnectionSettingsDiscovery {
override fun discover(email: String): DiscoveryResults? {
val domain = EmailHelper.getDomainFromEmailAddress(email) ?: return null
val provider = findProviderForDomain(domain) ?: return null
val incomingSettings = provider.toIncomingServerSettings(email) ?: return null
val outgoingSettings = provider.toOutgoingServerSettings(email) ?: return null
return DiscoveryResults(listOf(incomingSettings), listOf(outgoingSettings))
}
private fun findProviderForDomain(domain: String): Provider? {
return try {
xmlProvider.getXml().use { xml ->
parseProviders(xml, domain)
}
} catch (e: Exception) {
Timber.e(e, "Error while trying to load provider settings.")
null
}
}
private fun parseProviders(xml: XmlResourceParser, domain: String): Provider? {
do {
val xmlEventType = xml.next()
if (xmlEventType == XmlPullParser.START_TAG && xml.name == "provider") {
val providerDomain = xml.getAttributeValue(null, "domain")
if (domain.equals(providerDomain, ignoreCase = true)) {
val provider = parseProvider(xml)
if (provider != null) return provider
}
}
} while (xmlEventType != XmlPullParser.END_DOCUMENT)
return null
}
private fun parseProvider(xml: XmlResourceParser): Provider? {
var incomingUriTemplate: String? = null
var incomingUsernameTemplate: String? = null
var outgoingUriTemplate: String? = null
var outgoingUsernameTemplate: String? = null
do {
val xmlEventType = xml.next()
if (xmlEventType == XmlPullParser.START_TAG) {
when (xml.name) {
"incoming" -> {
incomingUriTemplate = xml.getAttributeValue(null, "uri")
incomingUsernameTemplate = xml.getAttributeValue(null, "username")
}
"outgoing" -> {
outgoingUriTemplate = xml.getAttributeValue(null, "uri")
outgoingUsernameTemplate = xml.getAttributeValue(null, "username")
}
}
}
} while (!(xmlEventType == XmlPullParser.END_TAG && xml.name == "provider"))
return if (incomingUriTemplate != null && incomingUsernameTemplate != null && outgoingUriTemplate != null &&
outgoingUsernameTemplate != null
) {
Provider(incomingUriTemplate, incomingUsernameTemplate, outgoingUriTemplate, outgoingUsernameTemplate)
} else {
null
}
}
private fun Provider.toIncomingServerSettings(email: String): DiscoveredServerSettings? {
val user = EmailHelper.getLocalPartFromEmailAddress(email) ?: return null
val domain = EmailHelper.getDomainFromEmailAddress(email) ?: return null
val username = incomingUsernameTemplate.fillInUsernameTemplate(email, user, domain)
val security = when {
incomingUriTemplate.startsWith("imap+ssl") -> ConnectionSecurity.SSL_TLS_REQUIRED
incomingUriTemplate.startsWith("imap+tls") -> ConnectionSecurity.STARTTLS_REQUIRED
else -> error("Connection security required")
}
val uri = Uri.parse(incomingUriTemplate)
val host = uri.host ?: error("Host name required")
val port = if (uri.port == -1) {
if (security == ConnectionSecurity.STARTTLS_REQUIRED) 143 else 993
} else {
uri.port
}
val authType = if (oAuthConfigurationProvider.getConfiguration(host) != null) {
AuthType.XOAUTH2
} else {
AuthType.PLAIN
}
return DiscoveredServerSettings(Protocols.IMAP, host, port, security, authType, username)
}
private fun Provider.toOutgoingServerSettings(email: String): DiscoveredServerSettings? {
val user = EmailHelper.getLocalPartFromEmailAddress(email) ?: return null
val domain = EmailHelper.getDomainFromEmailAddress(email) ?: return null
val username = outgoingUsernameTemplate.fillInUsernameTemplate(email, user, domain)
val security = when {
outgoingUriTemplate.startsWith("smtp+ssl") -> ConnectionSecurity.SSL_TLS_REQUIRED
outgoingUriTemplate.startsWith("smtp+tls") -> ConnectionSecurity.STARTTLS_REQUIRED
else -> error("Connection security required")
}
val uri = Uri.parse(outgoingUriTemplate)
val host = uri.host ?: error("Host name required")
val port = if (uri.port == -1) {
if (security == ConnectionSecurity.STARTTLS_REQUIRED) 587 else 465
} else {
uri.port
}
val authType = if (oAuthConfigurationProvider.getConfiguration(host) != null) {
AuthType.XOAUTH2
} else {
AuthType.PLAIN
}
return DiscoveredServerSettings(Protocols.SMTP, host, port, security, authType, username)
}
private fun String.fillInUsernameTemplate(email: String, user: String, domain: String): String {
return this.replace("\$email", email).replace("\$user", user).replace("\$domain", domain)
}
internal data class Provider(
val incomingUriTemplate: String,
val incomingUsernameTemplate: String,
val outgoingUriTemplate: String,
val outgoingUsernameTemplate: String
)
}

View file

@ -0,0 +1,10 @@
package com.fsck.k9.autodiscovery.providersxml
import android.content.Context
import android.content.res.XmlResourceParser
class ProvidersXmlProvider(private val context: Context) {
fun getXml(): XmlResourceParser {
return context.resources.getXml(R.xml.providers)
}
}

View file

@ -0,0 +1,774 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!--
This file is used to specify providers that we know default settings for
so that the user can set up their account by simply entering their email
address and password.
When a user starts this process, the email address is parsed, the domain
broken out and used to search this file for a provider. If one is found the
provider's settings are used to attempt to connect to the account.
At this time, the id and label attributes are not used. However, please include them
if you make edits to this file. id must also be completely unique. label will be shown
to the user when there are multiple options provided for a single domain (not currently
supported).
A provider contains the settings for setting up an email account
that ends with the given domain. Domains should be unique within
this file. Each provider should have at least one incoming section and
one outgoing section. If more than one is specified only the first
will be used.
Valid incoming uri schemes are:
imap+tls+ IMAP with required TLS transport security.
If TLS is not available the connection fails.
imap+ssl+ IMAP with required SSL transport security.
If SSL is not available the connection fails.
Valid outgoing uri schemes are:
smtp+tls+ SMTP with required TLS transport security.
If TLS is not available the connection fails.
smtp+ssl+ SMTP with required SSL transport security.
If SSL is not available the connection fails.
The URIs should be full templates for connection, including a port if
the service uses a non-default port. The default ports are as follows:
imap+tls+ 143 smtp+tls+ 587
imap+ssl+ 993 smtp+ssl+ 465
The username attribute is used to supply a template for the username
that will be presented to the server. This username is built from a
set of variables that are substituted with parts of the user
specified email address.
Valid substitution values for the username attribute are:
$email - the email address the user entered
$user - the value before the @ sign in the email address the user entered
$domain - the value after the @ sign in the email address the user entered
The username attribute MUST be specified for the incoming element, so the IMAP
server can identify the mailbox to be opened.
The username attribute MAY be the empty string for the outgoing element, but only if the
SMTP server supports anonymous transmission (most don't).
While it would technically work please DO NOT add providers that don't support encrypted
connections.
-->
<providers>
<!-- Gmail variants -->
<provider id="gmail" label="Gmail" domain="gmail.com">
<incoming uri="imap+ssl+://imap.gmail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.gmail.com" username="$email" />
</provider>
<provider id="googlemail" label="Google Mail" domain="googlemail.com">
<incoming uri="imap+ssl+://imap.googlemail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.googlemail.com" username="$email" />
</provider>
<provider id="google" label="Google" domain="google.com">
<incoming uri="imap+ssl+://imap.gmail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.gmail.com" username="$email" />
</provider>
<provider id="android" label="Android" domain="android.com">
<incoming uri="imap+ssl+://imap.gmail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.gmail.com" username="$email" />
</provider>
<!-- USA -->
<provider id="comcast" label="Comcast" domain="comcast.net">
<incoming uri="imap+ssl+://imap.comcast.net" username="$email" />
<outgoing uri="smtp+tls+://smtp.comcast.net" username="$email" />
</provider>
<provider id="montclair.edu" label="MSU" domain="montclair.edu">
<incoming uri="imap+ssl+://mail.montclair.edu" username="$user" />
<outgoing uri="smtp+tls+://smtp.montclair.edu" username="$user" />
</provider>
<provider id="gmx.com" label="GMX" domain="gmx.com">
<incoming uri="imap+ssl+://imap.gmx.com" username="$email" />
<outgoing uri="smtp+ssl+://mail.gmx.com" username="$email" />
</provider>
<provider id="zoho.com" label="Zoho Mail" domain="zoho.com">
<incoming uri="imap+ssl+://imap.zoho.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.zoho.com" username="$email" />
</provider>
<provider id="riseup" label="Riseup Networks" domain="riseup.net">
<incoming uri="imap+ssl+://mail.riseup.net" username="$user" />
<outgoing uri="smtp+tls+://mail.riseup.net" username="$user" />
</provider>
<!-- Mail.com Variants -->
<provider id="mail.com" label="Mail.com" domain="mail.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="email.com" label="Mail.com" domain="email.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="techie.com" label="Mail.com" domain="techie.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="email.com" label="Mail.com" domain="email.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="usa.com" label="Mail.com" domain="usa.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="myself.com" label="Mail.com" domain="myself.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="consultant.com" label="Mail.com" domain="consultant.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="post.com" label="Mail.com" domain="post.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="europe.com" label="Mail.com" domain="europe.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="asia.com" label="Mail.com" domain="asia.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="iname.com" label="Mail.com" domain="iname.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="writeme.com" label="Mail.com" domain="writeme.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="dr.com" label="Mail.com" domain="dr.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="engineer.com" label="Mail.com" domain="engineer.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="cheerful.com" label="Mail.com" domain="cheerful.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="accountant.com" label="Mail.com" domain="accountant.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="techie.com" label="Mail.com" domain="techie.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="linuxmail.org" label="Mail.com" domain="linuxmail.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="uymail.com" label="Mail.com" domain="uymail.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<provider id="contractor.net" label="Mail.com" domain="contractor.com">
<incoming uri="imap+ssl+://imap.mail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.com" username="$email" />
</provider>
<!-- Yahoo! Mail Variants -->
<provider id="yahoo" label="Yahoo" domain="yahoo.com">
<incoming uri="imap+ssl+://imap.mail.yahoo.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.yahoo.com" username="$email" />
</provider>
<provider id="yahoo.de" label="Yahoo" domain="yahoo.de">
<incoming uri="imap+ssl+://imap.mail.yahoo.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.yahoo.com" username="$email" />
</provider>
<provider id="ymail" label="YMail" domain="ymail.com">
<incoming uri="imap+ssl+://imap.mail.yahoo.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.yahoo.com" username="$email" />
</provider>
<provider id="rocketmail" label="Rocketmail" domain="rocketmail.com">
<incoming uri="imap+ssl+://imap.mail.yahoo.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.yahoo.com" username="$email" />
</provider>
<!-- Apple -->
<provider id="apple" label="Apple" domain="apple.com">
<incoming uri="imap+ssl+://imap.mail.apple.com" username="$user" />
<outgoing uri="smtp+tls+://smtp.mail.apple.com" username="$user" />
</provider>
<provider id="dotmac" label=".Mac" domain="mac.com">
<incoming uri="imap+ssl+://imap.mail.mac.com" username="$user" />
<outgoing uri="smtp+tls+://smtp.mail.mac.com" username="$user" />
</provider>
<provider id="mobileme" label="MobileMe" domain="me.com">
<incoming uri="imap+ssl+://imap.mail.me.com" username="$user" />
<outgoing uri="smtp+tls+://smtp.mail.me.com" username="$user" />
</provider>
<provider id="icloud" label="iCloud" domain="icloud.com">
<incoming uri="imap+ssl+://imap.mail.icloud.com" username="$user" />
<outgoing uri="smtp+tls+://smtp.mail.icloud.com" username="$user" />
</provider>
<!-- Australia -->
<provider id="fastmail-fm" label="Fastmail" domain="fastmail.fm">
<incoming uri="imap+ssl+://mail.messagingengine.com" username="$email" />
<outgoing uri="smtp+ssl+://mail.messagingengine.com" username="$email" />
</provider>
<!-- Virgin Media variants -->
<provider id="virginmedia.com" label="Virgin Media" domain="virginmedia.com">
<incoming uri="imap+ssl+://imap.virginmedia.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.virginmedia.com" username="$email" />
</provider>
<provider id="virgin.net" label="Virgin Media" domain="virgin.net">
<incoming uri="imap+ssl+://imap.virginmedia.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.virginmedia.com" username="$email" />
</provider>
<provider id="blueyonder.co.uk" label="Virgin Media" domain="blueyonder.co.uk">
<incoming uri="imap+ssl+://imap.virginmedia.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.virginmedia.com" username="$email" />
</provider>
<provider id="ntlworld.com" label="Virgin Media" domain="ntlworld.com">
<incoming uri="imap+ssl+://imap.virginmedia.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.virginmedia.com" username="$email" />
</provider>
<!-- France -->
<provider id="mailo.com" label="mailo.com" domain="mailo.com">
<incoming uri="imap+ssl+://mail.mailo.com" username="$email" />
<outgoing uri="smtp+ssl+://mail.mailo.com" username="$email" />
</provider>
<provider id="net-c.fr" label="net-c.fr" domain="net-c.fr">
<incoming uri="imap+ssl+://mail.mailo.com" username="$email" />
<outgoing uri="smtp+ssl+://mail.mailo.com" username="$email" />
</provider>
<!-- Germany -->
<provider id="mailbox.org" label="mailbox.org" domain="mailbox.org">
<incoming uri="imap+tls+://imap.mailbox.org" username="$email" />
<outgoing uri="smtp+tls+://smtp.mailbox.org" username="$email" />
</provider>
<provider id="freenet" label="Freenet" domain="freenet.de">
<incoming uri="imap+tls+://mx.freenet.de" username="$email" />
<outgoing uri="smtp+tls+://mx.freenet.de" username="$email" />
</provider>
<provider id="T-Online" label="T-Online" domain="t-online.de">
<incoming uri="imap+ssl+://secureimap.t-online.de" username="$email" />
<outgoing uri="smtp+tls+://securesmtp.t-online.de" username="$email" />
</provider>
<provider id="web.de" label="Web.de" domain="web.de">
<incoming uri="imap+ssl+://imap.web.de" username="$user" />
<outgoing uri="smtp+tls+://smtp.web.de" username="$user" />
</provider>
<provider id="posteo" label="Posteo" domain="posteo.net">
<incoming uri="imap+tls+://posteo.de" username="$email" />
<outgoing uri="smtp+tls+://posteo.de" username="$email" />
</provider>
<provider id="posteo" label="Posteo" domain="posteo.de">
<incoming uri="imap+tls+://posteo.de" username="$email" />
<outgoing uri="smtp+tls+://posteo.de" username="$email" />
</provider>
<provider id="systemliorg" label="systemli.org" domain="systemli.org">
<incoming uri="imap+ssl+://mail.systemli.org" username="$email" />
<outgoing uri="smtp+tls+://mail.systemli.org" username="$email" />
</provider>
<!-- GMX variants -->
<provider id="gmx.net" label="GMX.net" domain="gmx.net">
<incoming uri="imap+ssl+://imap.gmx.net" username="$email" />
<outgoing uri="smtp+tls+://mail.gmx.net" username="$email" />
</provider>
<provider id="gmx.de" label="GMX.de" domain="gmx.de">
<incoming uri="imap+ssl+://imap.gmx.net" username="$email" />
<outgoing uri="smtp+tls+://mail.gmx.net" username="$email" />
</provider>
<provider id="gmx.at" label="GMX.at" domain="gmx.at">
<incoming uri="imap+ssl+://imap.gmx.net" username="$email" />
<outgoing uri="smtp+tls+://mail.gmx.net" username="$email" />
</provider>
<provider id="gmx.ch" label="GMX.ch" domain="gmx.ch">
<incoming uri="imap+ssl+://imap.gmx.net" username="$email" />
<outgoing uri="smtp+tls+://mail.gmx.net" username="$email" />
</provider>
<provider id="gmx.eu" label="GMX.eu" domain="gmx.eu">
<incoming uri="imap+ssl+://imap.gmx.net" username="$email" />
<outgoing uri="smtp+tls+://mail.gmx.net" username="$email" />
</provider>
<!-- Greece -->
<provider id="otenet.gr" label="otenet.gr" domain="otenet.gr">
<incoming uri="imap+ssl+://imap.otenet.gr" username="$email" />
<outgoing uri="smtp+tls+://mailgate.otenet.gr" username="$email" />
</provider>
<provider id="cosmotemail.gr" label="cosmotemail" domain="cosmotemail.gr">
<incoming uri="imap+ssl+://imap.cosmotemail.gr" username="$email" />
<outgoing uri="smtp+tls+://mailgate.cosmotemail.gr" username="$email" />
</provider>
<provider id="mycosmos.gr" label="mycosmos" domain="mycosmos.gr">
<incoming uri="imap+ssl+://mail.mycosmos.gr" username="$email" />
<outgoing uri="smtp+tls+://mail.mycosmos.gr" username="$email" />
</provider>
<provider id="espiv" label="Espiv.net" domain="espiv.net">
<incoming uri="imap+ssl+://mail.espiv.net" username="$email" />
<outgoing uri="smtp+tls+://mail.espiv.net" username="$email" />
</provider>
<provider id="squat" label="Squat.gr" domain="squat.gr">
<incoming uri="imap+ssl+://mail.espiv.net" username="$email" />
<outgoing uri="smtp+tls+://mail.espiv.net" username="$email" />
</provider>
<!-- Italy -->
<provider id="poste" label="poste" domain="poste.it">
<incoming uri="imap+ssl+://relay.poste.it" username="$email" />
<outgoing uri="smtp+ssl+://relay.poste.it" username="$email" />
</provider>
<provider id="vodafone" label="vodafone" domain="vodafone.it">
<incoming uri="imap+ssl+://imap.vodafone.it" username="$email" />
<outgoing uri="smtp+ssl+://smtp.vodafone.it" username="$email" />
</provider>
<!-- Switzerland -->
<!-- KolabNow.com variants -->
<provider id="kolabnow.com" label="KolabNow.com" domain="kolabnow.com">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="attorneymail.ch" label="KolabNow.com" domain="attorneymail.ch">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="barmail.ch" label="KolabNow.com" domain="barmail.ch">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="collaborative.li" label="KolabNow.com" domain="collaborative.li">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="diplomail.ch" label="KolabNow.com" domain="diplomail.ch">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="groupoffice.ch" label="KolabNow.com" domain="groupoffice.ch">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="journalistmail.ch" label="KolabNow.com" domain="journalistmail.ch">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="legalprivilege.ch" label="KolabNow.com" domain="legalprivilege.ch">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="libertymail.co" label="KolabNow.com" domain="libertymail.co">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="libertymail.net" label="KolabNow.com" domain="libertymail.net">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="mailatlaw.ch" label="KolabNow.com" domain="mailatlaw.ch">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="medmail.ch" label="KolabNow.com" domain="medmail.ch">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="mykolab.ch" label="KolabNow.com" domain="mykolab.ch">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="mykolab.com" label="KolabNow.com" domain="mykolab.com">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="myswissmail.ch" label="KolabNow.com" domain="myswissmail.ch">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="opengroupware.ch" label="KolabNow.com" domain="opengroupware.ch">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="pressmail.ch" label="KolabNow.com" domain="pressmail.ch">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="swisscollab.ch" label="KolabNow.com" domain="swisscollab.ch">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="swissgroupware.ch" label="KolabNow.com" domain="swissgroupware.ch">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="switzerlandmail.ch" label="KolabNow.com" domain="switzerlandmail.ch">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<provider id="trusted-legal-mail.ch" label="KolabNow.com" domain="trusted-legal-mail.ch">
<incoming uri="imap+ssl+://imap.kolabnow.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.kolabnow.com" username="$email" />
</provider>
<!-- Japanese -->
<provider id="auone" label="au one" domain="auone.jp">
<incoming uri="imap+ssl+://imap.gmail.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.gmail.com" username="$email" />
</provider>
<!-- Korean -->
<provider id="naver" label="Naver" domain="naver.com">
<incoming uri="imap+ssl+://imap.naver.com" username="$user" />
<outgoing uri="smtp+tls+://smtp.naver.com:587" username="$user" />
</provider>
<provider id="hanmail" label="Hanmail" domain="hanmail.net">
<incoming uri="imap+ssl+://imap.hanmail.net" username="$user" />
<outgoing uri="smtp+ssl+://smtp.hanmail.net" username="$user" />
</provider>
<provider id="daum" label="Hanmail" domain="daum.net">
<incoming uri="imap+ssl+://imap.hanmail.net" username="$user" />
<outgoing uri="smtp+ssl+://smtp.hanmail.net" username="$user" />
</provider>
<!-- Russia -->
<!-- Mail.Ru variants -->
<provider id="rumailmailimap" label="mail.ru" domain="mail.ru">
<incoming uri="imap+ssl+://imap.mail.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.ru" username="$email" />
</provider>
<provider id="rumailinboximap" label="inbox.ru" domain="inbox.ru">
<incoming uri="imap+ssl+://imap.mail.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.ru" username="$email" />
</provider>
<provider id="rumaillistimap" label="list.ru" domain="list.ru">
<incoming uri="imap+ssl+://imap.mail.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.ru" username="$email" />
</provider>
<provider id="rumailbkimap" label="bk.ru" domain="bk.ru">
<incoming uri="imap+ssl+://imap.mail.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.ru" username="$email" />
</provider>
<!-- Yandex variants -->
<provider id="comyanyandeximap" label="yandex.com" domain="yandex.com">
<incoming uri="imap+ssl+://imap.yandex.com" username="$user" />
<outgoing uri="smtp+ssl+://smtp.yandex.com" username="$user" />
</provider>
<provider id="ruyanyandeximap" label="yandex.ru" domain="yandex.ru">
<incoming uri="imap+ssl+://imap.yandex.ru" username="$user" />
<outgoing uri="smtp+ssl+://smtp.yandex.ru" username="$user" />
</provider>
<provider id="ruyanyaimap" label="ya.ru" domain="ya.ru">
<incoming uri="imap+ssl+://imap.ya.ru" username="$user" />
<outgoing uri="smtp+ssl+://smtp.ya.ru" username="$user" />
</provider>
<provider id="byyandeximap" label="yandex.by" domain="yandex.by">
<incoming uri="imap+ssl+://imap.yandex.by" username="$user" />
<outgoing uri="smtp+ssl+://smtp.yandex.by" username="$user" />
</provider>
<provider id="kzyandeximap" label="yandex.kz" domain="yandex.kz">
<incoming uri="imap+ssl+://imap.yandex.kz" username="$user" />
<outgoing uri="smtp+ssl+://smtp.yandex.kz" username="$user" />
</provider>
<provider id="uayandeximap" label="yandex.ua" domain="yandex.ua">
<incoming uri="imap+ssl+://imap.yandex.ua" username="$user" />
<outgoing uri="smtp+ssl+://smtp.yandex.ua" username="$user" />
</provider>
<!-- Rambler.ru variants -->
<provider id="ruramramblerimap" label="rambler.ru" domain="rambler.ru">
<incoming uri="imap+ssl+://mail.rambler.ru" username="$email" />
<outgoing uri="smtp+ssl+://mail.rambler.ru" username="$email" />
</provider>
<provider id="ruramlentaimap" label="lenta.ru" domain="lenta.ru">
<incoming uri="imap+ssl+://mail.rambler.ru" username="$email" />
<outgoing uri="smtp+ssl+://mail.rambler.ru" username="$email" />
</provider>
<provider id="ruramroimap" label="ro.ru" domain="ro.ru">
<incoming uri="imap+ssl+://mail.rambler.ru" username="$email" />
<outgoing uri="smtp+ssl+://mail.rambler.ru" username="$email" />
</provider>
<!-- QIP.RU variants -->
<provider id="ruqipqipimap" label="qip.ru" domain="qip.ru">
<incoming uri="imap+ssl+://imap.qip.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.qip.ru" username="$email" />
</provider>
<provider id="ruqippochtaimap" label="pochta.ru" domain="pochta.ru">
<incoming uri="imap+ssl+://imap.pochta.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.pochta.ru" username="$email" />
</provider>
<provider id="comqipfromruimap" label="fromru.com" domain="fromru.com">
<incoming uri="imap+ssl+://imap.fromru.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.fromru.com" username="$email" />
</provider>
<provider id="ruqipfrontimap" label="front.ru" domain="front.ru">
<incoming uri="imap+ssl+://imap.front.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.front.ru" username="$email" />
</provider>
<provider id="ruqiphotboximap" label="hotbox.ru" domain="hotbox.ru">
<incoming uri="imap+ssl+://imap.hotbox.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.hotbox.ru" username="$email" />
</provider>
<provider id="ruqiphotmailimap" label="hotmail.ru" domain="hotmail.ru">
<incoming uri="imap+ssl+://imap.hotmail.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.hotmail.ru" username="$email" />
</provider>
<provider id="suqipkrovatkaimap" label="krovatka.su" domain="krovatka.su">
<incoming uri="imap+ssl+://imap.krovatka.su" username="$email" />
<outgoing uri="smtp+ssl+://smtp.krovatka.su" username="$email" />
</provider>
<provider id="ruqiplandimap" label="land.ru" domain="land.ru">
<incoming uri="imap+ssl+://imap.land.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.land.ru" username="$email" />
</provider>
<provider id="comqipmail15imap" label="mail15.com" domain="mail15.com">
<incoming uri="imap+ssl+://imap.mail15.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail15.com" username="$email" />
</provider>
<provider id="comqipmail333imap" label="mail333.com" domain="mail333.com">
<incoming uri="imap+ssl+://imap.mail333.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail333.com" username="$email" />
</provider>
<provider id="ruqipnewmailimap" label="newmail.ru" domain="newmail.ru">
<incoming uri="imap+ssl+://imap.newmail.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.newmail.ru" username="$email" />
</provider>
<provider id="ruqipnightmailimap" label="nightmail.ru" domain="nightmail.ru">
<incoming uri="imap+ssl+://imap.nightmail.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.nightmail.ru" username="$email" />
</provider>
<provider id="ruqipnmimap" label="nm.ru" domain="nm.ru">
<incoming uri="imap+ssl+://imap.nm.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.nm.ru" username="$email" />
</provider>
<provider id="netqippisemimap" label="pisem.net" domain="pisem.net">
<incoming uri="imap+ssl+://imap.pisem.net" username="$email" />
<outgoing uri="smtp+ssl+://smtp.pisem.net" username="$email" />
</provider>
<provider id="ruqippochtamtimap" label="pochtamt.ru" domain="pochtamt.ru">
<incoming uri="imap+ssl+://imap.pochtamt.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.pochtamt.ru" username="$email" />
</provider>
<provider id="ruqippop3imap" label="pop3.ru" domain="pop3.ru">
<incoming uri="imap+ssl+://imap.pop3.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.pop3.ru" username="$email" />
</provider>
<provider id="ruqiprbcmailimap" label="rbcmail.ru" domain="rbcmail.ru">
<incoming uri="imap+ssl+://imap.rbcmail.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.rbcmail.ru" username="$email" />
</provider>
<provider id="ruqipsmtpimap" label="smtp.ru" domain="smtp.ru">
<incoming uri="imap+ssl+://imap.smtp.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.smtp.ru" username="$email" />
</provider>
<provider id="ruqip5ballovimap" label="5ballov.ru" domain="5ballov.ru">
<incoming uri="imap+ssl+://imap.5ballov.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.5ballov.ru" username="$email" />
</provider>
<provider id="ruqipaeternaimap" label="aeterna.ru" domain="aeterna.ru">
<incoming uri="imap+ssl+://imap.aeterna.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.aeterna.ru" username="$email" />
</provider>
<provider id="ruqipzizaimap" label="ziza.ru" domain="ziza.ru">
<incoming uri="imap+ssl+://imap.ziza.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.ziza.ru" username="$email" />
</provider>
<provider id="ruqipmemoriimap" label="memori.ru" domain="memori.ru">
<incoming uri="imap+ssl+://imap.memori.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.memori.ru" username="$email" />
</provider>
<provider id="ruqipphotofileimap" label="photofile.ru" domain="photofile.ru">
<incoming uri="imap+ssl+://imap.photofile.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.photofile.ru" username="$email" />
</provider>
<provider id="ruqipfotoplenkaimap" label="fotoplenka.ru" domain="fotoplenka.ru">
<incoming uri="imap+ssl+://imap.fotoplenka.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.fotoplenka.ru" username="$email" />
</provider>
<provider id="comqippochtaimap" label="pochta.com" domain="pochta.com">
<incoming uri="imap+ssl+://imap.pochta.ru" username="$email" />
<outgoing uri="smtp+ssl+://smtp.pochta.ru" username="$email" />
</provider>
<!-- Slovakia -->
<provider id="azet.sk" label="Azet.sk" domain="azet.sk">
<incoming uri="imap+ssl+://imap.azet.sk" username="$email" />
<outgoing uri="smtp+ssl+://smtp.azet.sk" username="$email" />
</provider>
<!-- The Netherlands -->
<!-- Ziggo variants -->
<provider id="casema.nl" label="Ziggo" domain="casema.nl">
<incoming uri="imap+ssl+://imap.ziggo.nl" username="$email" />
<outgoing uri="smtp+tls+://smtp.ziggo.nl" username="$email" />
</provider>
<provider id="chello.nl" label="Ziggo" domain="chello.nl">
<incoming uri="imap+ssl+://imap.ziggo.nl" username="$email" />
<outgoing uri="smtp+tls+://smtp.ziggo.nl" username="$email" />
</provider>
<provider id="hahah.nl" label="Ziggo" domain="hahah.nl">
<incoming uri="imap+ssl+://imap.ziggo.nl" username="$email" />
<outgoing uri="smtp+tls+://smtp.ziggo.nl" username="$email" />
</provider>
<provider id="home.nl" label="Ziggo" domain="home.nl">
<incoming uri="imap+ssl+://imap.ziggo.nl" username="$email" />
<outgoing uri="smtp+tls+://smtp.ziggo.nl" username="$email" />
</provider>
<provider id="multiweb.nl" label="Ziggo" domain="multiweb.nl">
<incoming uri="imap+ssl+://imap.ziggo.nl" username="$email" />
<outgoing uri="smtp+tls+://smtp.ziggo.nl" username="$email" />
</provider>
<provider id="quicknet.nl" label="Ziggo" domain="quicknet.nl">
<incoming uri="imap+ssl+://imap.ziggo.nl" username="$email" />
<outgoing uri="smtp+tls+://smtp.ziggo.nl" username="$email" />
</provider>
<provider id="razcall.com" label="Ziggo" domain="razcall.com">
<incoming uri="imap+ssl+://imap.ziggo.nl" username="$email" />
<outgoing uri="smtp+tls+://smtp.ziggo.nl" username="$email" />
</provider>
<provider id="razcall.nl" label="Ziggo" domain="razcall.nl">
<incoming uri="imap+ssl+://imap.ziggo.nl" username="$email" />
<outgoing uri="smtp+tls+://smtp.ziggo.nl" username="$email" />
</provider>
<provider id="upcmail.nl" label="Ziggo" domain="upcmail.nl">
<incoming uri="imap+ssl+://imap.ziggo.nl" username="$email" />
<outgoing uri="smtp+tls+://smtp.ziggo.nl" username="$email" />
</provider>
<provider id="zeggis.com" label="Ziggo" domain="zeggis.com">
<incoming uri="imap+ssl+://imap.ziggo.nl" username="$email" />
<outgoing uri="smtp+tls+://smtp.ziggo.nl" username="$email" />
</provider>
<provider id="zeggis.nl" label="Ziggo" domain="zeggis.nl">
<incoming uri="imap+ssl+://imap.ziggo.nl" username="$email" />
<outgoing uri="smtp+tls+://smtp.ziggo.nl" username="$email" />
</provider>
<provider id="ziggomail.com" label="Ziggo" domain="ziggomail.com">
<incoming uri="imap+ssl+://imap.ziggo.nl" username="$email" />
<outgoing uri="smtp+tls+://smtp.ziggo.nl" username="$email" />
</provider>
<provider id="ziggo.nl" label="Ziggo" domain="ziggo.nl">
<incoming uri="imap+ssl+://imap.ziggo.nl" username="$email" />
<outgoing uri="smtp+tls+://smtp.ziggo.nl" username="$email" />
</provider>
<provider id="zinders.nl" label="Ziggo" domain="zinders.nl">
<incoming uri="imap+ssl+://imap.ziggo.nl" username="$email" />
<outgoing uri="smtp+tls+://smtp.ziggo.nl" username="$email" />
</provider>
<!-- EU wide -->
<provider id="fairnatics.net" label="Fairnatics" domain="fairnatics.net">
<incoming uri="imap+ssl+://mail.fairnatics.net" username="$email" />
<outgoing uri="smtp+tls+://mail.fairnatics.net:25" username="$email" />
</provider>
<!-- eFoundation -->
<provider id="e.foundation" label="/e/" domain="e.email">
<incoming uri="imap+ssl+://mail.ecloud.global" username="$email" />
<outgoing uri="smtp+tls+://mail.ecloud.global" username="$email" />
</provider>
<!-- AOL variants -->
<provider domain="aol.com">
<incoming uri="imap+ssl+://imap.aol.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.aol.com" username="$email" />
</provider>
<provider domain="aol.de">
<incoming uri="imap+ssl+://imap.aol.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.aol.com" username="$email" />
</provider>
<provider domain="aol.it">
<incoming uri="imap+ssl+://imap.aol.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.aol.com" username="$email" />
</provider>
<provider domain="aol.fr">
<incoming uri="imap+ssl+://imap.aol.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.aol.com" username="$email" />
</provider>
<provider domain="aol.es">
<incoming uri="imap+ssl+://imap.aol.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.aol.com" username="$email" />
</provider>
<provider domain="aol.se">
<incoming uri="imap+ssl+://imap.aol.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.aol.com" username="$email" />
</provider>
<provider domain="aol.co.uk">
<incoming uri="imap+ssl+://imap.aol.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.aol.com" username="$email" />
</provider>
<provider domain="aol.co.nz">
<incoming uri="imap+ssl+://imap.aol.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.aol.com" username="$email" />
</provider>
<provider domain="aol.com.au">
<incoming uri="imap+ssl+://imap.aol.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.aol.com" username="$email" />
</provider>
<provider domain="aol.com.ar">
<incoming uri="imap+ssl+://imap.aol.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.aol.com" username="$email" />
</provider>
<provider domain="aol.com.br">
<incoming uri="imap+ssl+://imap.aol.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.aol.com" username="$email" />
</provider>
<provider domain="aol.com.mx">
<incoming uri="imap+ssl+://imap.aol.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.aol.com" username="$email" />
</provider>
<!-- Microsoft variants -->
<provider domain="outlook.com">
<incoming uri="imap+ssl+://outlook.office365.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.office365.com" username="$email" />
</provider>
<provider domain="hotmail.com">
<incoming uri="imap+ssl+://outlook.office365.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.office365.com" username="$email" />
</provider>
<provider domain="msn.com">
<incoming uri="imap+ssl+://outlook.office365.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.office365.com" username="$email" />
</provider>
<provider domain="live.com">
<incoming uri="imap+ssl+://outlook.office365.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.office365.com" username="$email" />
</provider>
<provider domain="live.co.uk">
<incoming uri="imap+ssl+://outlook.office365.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.office365.com" username="$email" />
</provider>
<provider domain="hotmail.co.uk">
<incoming uri="imap+ssl+://outlook.office365.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.office365.com" username="$email" />
</provider>
<provider domain="outlook.sk">
<incoming uri="imap+ssl+://outlook.office365.com" username="$email" />
<outgoing uri="smtp+tls+://smtp.office365.com" username="$email" />
</provider>
</providers>

View file

@ -0,0 +1,64 @@
package com.fsck.k9.autodiscovery.providersxml
import androidx.test.core.app.ApplicationProvider
import assertk.assertThat
import assertk.assertions.isEqualTo
import assertk.assertions.isNotNull
import assertk.assertions.isNull
import com.fsck.k9.RobolectricTest
import com.fsck.k9.mail.AuthType
import com.fsck.k9.mail.ConnectionSecurity
import com.fsck.k9.oauth.OAuthConfiguration
import com.fsck.k9.oauth.OAuthConfigurationProvider
import org.junit.Test
class ProvidersXmlDiscoveryTest : RobolectricTest() {
private val xmlProvider = ProvidersXmlProvider(ApplicationProvider.getApplicationContext())
private val oAuthConfigurationProvider = createOAuthConfigurationProvider()
private val providersXmlDiscovery = ProvidersXmlDiscovery(xmlProvider, oAuthConfigurationProvider)
@Test
fun discover_withGmailDomain_shouldReturnCorrectSettings() {
val connectionSettings = providersXmlDiscovery.discover("user@gmail.com")
assertThat(connectionSettings).isNotNull()
with(connectionSettings!!.incoming.first()) {
assertThat(host).isEqualTo("imap.gmail.com")
assertThat(security).isEqualTo(ConnectionSecurity.SSL_TLS_REQUIRED)
assertThat(authType).isEqualTo(AuthType.XOAUTH2)
assertThat(username).isEqualTo("user@gmail.com")
}
with(connectionSettings.outgoing.first()) {
assertThat(host).isEqualTo("smtp.gmail.com")
assertThat(security).isEqualTo(ConnectionSecurity.SSL_TLS_REQUIRED)
assertThat(authType).isEqualTo(AuthType.XOAUTH2)
assertThat(username).isEqualTo("user@gmail.com")
}
}
@Test
fun discover_withUnknownDomain_shouldReturnNull() {
val connectionSettings = providersXmlDiscovery.discover(
"user@not.present.in.providers.xml.example"
)
assertThat(connectionSettings).isNull()
}
private fun createOAuthConfigurationProvider(): OAuthConfigurationProvider {
val googleConfig = OAuthConfiguration(
clientId = "irrelevant",
scopes = listOf("irrelevant"),
authorizationEndpoint = "irrelevant",
tokenEndpoint = "irrelevant",
redirectUri = "irrelevant"
)
return OAuthConfigurationProvider(
configurations = mapOf(
listOf("imap.gmail.com", "smtp.gmail.com") to googleConfig
),
googleConfiguration = googleConfig
)
}
}

View file

@ -0,0 +1,11 @@
@Suppress("DSL_SCOPE_VIOLATION")
plugins {
id(ThunderbirdPlugins.Library.jvm)
alias(libs.plugins.android.lint)
}
dependencies {
api(projects.app.autodiscovery.api)
implementation(libs.minidns.hla)
}

View file

@ -0,0 +1,29 @@
package com.fsck.k9.autodiscovery.srvrecords
import com.fsck.k9.mail.ConnectionSecurity.SSL_TLS_REQUIRED
import com.fsck.k9.mail.ConnectionSecurity.STARTTLS_REQUIRED
import org.minidns.dnslabel.DnsLabel
import org.minidns.dnsname.DnsName
import org.minidns.hla.ResolverApi
import org.minidns.hla.srv.SrvProto
class MiniDnsSrvResolver : SrvResolver {
override fun lookup(domain: String, type: SrvType): List<MailService> {
val result = ResolverApi.INSTANCE.resolveSrv(
DnsLabel.from(type.label),
SrvProto.tcp.dnsLabel,
DnsName.from(domain)
)
val security = if (type.assumeTls) SSL_TLS_REQUIRED else STARTTLS_REQUIRED
return result.answersOrEmptySet.map {
MailService(
srvType = type,
host = it.target.toString(),
port = it.port,
priority = it.priority,
security = security
)
}
}
}

View file

@ -0,0 +1,5 @@
package com.fsck.k9.autodiscovery.srvrecords
interface SrvResolver {
fun lookup(domain: String, type: SrvType): List<MailService>
}

View file

@ -0,0 +1,56 @@
package com.fsck.k9.autodiscovery.srvrecords
import com.fsck.k9.autodiscovery.api.ConnectionSettingsDiscovery
import com.fsck.k9.autodiscovery.api.DiscoveredServerSettings
import com.fsck.k9.autodiscovery.api.DiscoveryResults
import com.fsck.k9.helper.EmailHelper
import com.fsck.k9.mail.AuthType
import com.fsck.k9.mail.ConnectionSecurity
class SrvServiceDiscovery(
private val srvResolver: MiniDnsSrvResolver
) : ConnectionSettingsDiscovery {
override fun discover(email: String): DiscoveryResults? {
val domain = EmailHelper.getDomainFromEmailAddress(email) ?: return null
val mailServicePriority = compareBy<MailService> { it.priority }.thenByDescending { it.security }
val outgoingSettings = listOf(SrvType.SUBMISSIONS, SrvType.SUBMISSION)
.flatMap { srvResolver.lookup(domain, it) }
.sortedWith(mailServicePriority)
.map { newServerSettings(it, email) }
val incomingSettings = listOf(SrvType.IMAPS, SrvType.IMAP)
.flatMap { srvResolver.lookup(domain, it) }
.sortedWith(mailServicePriority)
.map { newServerSettings(it, email) }
return DiscoveryResults(incoming = incomingSettings, outgoing = outgoingSettings)
}
}
fun newServerSettings(service: MailService, email: String): DiscoveredServerSettings {
return DiscoveredServerSettings(
service.srvType.protocol,
service.host,
service.port,
service.security,
AuthType.PLAIN,
email
)
}
enum class SrvType(val label: String, val protocol: String, val assumeTls: Boolean) {
SUBMISSIONS("_submissions", "smtp", true),
SUBMISSION("_submission", "smtp", false),
IMAPS("_imaps", "imap", true),
IMAP("_imap", "imap", false)
}
data class MailService(
val srvType: SrvType,
val host: String,
val port: Int,
val priority: Int,
val security: ConnectionSecurity
)

View file

@ -0,0 +1,178 @@
package com.fsck.k9.autodiscovery.srvrecords
import com.fsck.k9.autodiscovery.api.DiscoveryResults
import com.fsck.k9.mail.ConnectionSecurity
import org.junit.Assert.assertEquals
import org.junit.Test
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
class SrvServiceDiscoveryTest {
@Test
fun discover_whenNoMailServices_shouldReturnNoResults() {
val srvResolver = newMockSrvResolver()
val srvServiceDiscovery = SrvServiceDiscovery(srvResolver)
val result = srvServiceDiscovery.discover("test@example.com")
assertEquals(DiscoveryResults(listOf(), listOf()), result)
}
@Test
fun discover_whenNoSMTP_shouldReturnJustIMAP() {
val srvResolver = newMockSrvResolver(
imapServices = listOf(newMailService(port = 143, srvType = SrvType.IMAP)),
imapsServices = listOf(
newMailService(port = 993, srvType = SrvType.IMAPS, security = ConnectionSecurity.SSL_TLS_REQUIRED)
)
)
val srvServiceDiscovery = SrvServiceDiscovery(srvResolver)
val result = srvServiceDiscovery.discover("test@example.com")
assertEquals(2, result!!.incoming.size)
assertEquals(0, result.outgoing.size)
}
@Test
fun discover_whenNoIMAP_shouldReturnJustSMTP() {
val srvResolver = newMockSrvResolver(
submissionServices = listOf(
newMailService(
port = 25,
srvType = SrvType.SUBMISSION,
security = ConnectionSecurity.STARTTLS_REQUIRED
),
newMailService(
port = 465,
srvType = SrvType.SUBMISSIONS,
security = ConnectionSecurity.SSL_TLS_REQUIRED
)
)
)
val srvServiceDiscovery = SrvServiceDiscovery(srvResolver)
val result = srvServiceDiscovery.discover("test@example.com")
assertEquals(0, result!!.incoming.size)
assertEquals(2, result.outgoing.size)
}
@Test
fun discover_withRequiredServices_shouldCorrectlyPrioritize() {
val srvResolver = newMockSrvResolver(
submissionServices = listOf(
newMailService(
host = "smtp1.example.com",
port = 25,
srvType = SrvType.SUBMISSION,
security = ConnectionSecurity.STARTTLS_REQUIRED,
priority = 0
),
newMailService(
host = "smtp2.example.com",
port = 25,
srvType = SrvType.SUBMISSION,
security = ConnectionSecurity.STARTTLS_REQUIRED,
priority = 1
)
),
submissionsServices = listOf(
newMailService(
host = "smtp3.example.com",
port = 465,
srvType = SrvType.SUBMISSIONS,
security = ConnectionSecurity.SSL_TLS_REQUIRED,
priority = 0
),
newMailService(
host = "smtp4.example.com",
port = 465,
srvType = SrvType.SUBMISSIONS,
security = ConnectionSecurity.SSL_TLS_REQUIRED,
priority = 1
)
),
imapServices = listOf(
newMailService(
host = "imap1.example.com",
port = 143,
srvType = SrvType.IMAP,
security = ConnectionSecurity.STARTTLS_REQUIRED,
priority = 0
),
newMailService(
host = "imap2.example.com",
port = 143,
srvType = SrvType.IMAP,
security = ConnectionSecurity.STARTTLS_REQUIRED,
priority = 1
)
),
imapsServices = listOf(
newMailService(
host = "imaps1.example.com",
port = 993,
srvType = SrvType.IMAPS,
security = ConnectionSecurity.SSL_TLS_REQUIRED,
priority = 0
),
newMailService(
host = "imaps2.example.com",
port = 993,
srvType = SrvType.IMAPS,
security = ConnectionSecurity.SSL_TLS_REQUIRED,
priority = 1
)
)
)
val srvServiceDiscovery = SrvServiceDiscovery(srvResolver)
val result = srvServiceDiscovery.discover("test@example.com")
assertEquals(
listOf(
"smtp3.example.com",
"smtp1.example.com",
"smtp4.example.com",
"smtp2.example.com"
),
result?.outgoing?.map { it.host }
)
assertEquals(
listOf(
"imaps1.example.com",
"imap1.example.com",
"imaps2.example.com",
"imap2.example.com"
),
result?.incoming?.map { it.host }
)
}
private fun newMailService(
host: String = "example.com",
priority: Int = 0,
security: ConnectionSecurity = ConnectionSecurity.STARTTLS_REQUIRED,
srvType: SrvType,
port: Int
): MailService {
return MailService(srvType, host, port, priority, security)
}
private fun newMockSrvResolver(
host: String = "example.com",
submissionServices: List<MailService> = listOf(),
submissionsServices: List<MailService> = listOf(),
imapServices: List<MailService> = listOf(),
imapsServices: List<MailService> = listOf()
): MiniDnsSrvResolver {
return mock {
on { lookup(host, SrvType.SUBMISSION) } doReturn submissionServices
on { lookup(host, SrvType.SUBMISSIONS) } doReturn submissionsServices
on { lookup(host, SrvType.IMAP) } doReturn imapServices
on { lookup(host, SrvType.IMAPS) } doReturn imapsServices
}
}
}

View file

@ -0,0 +1,15 @@
@Suppress("DSL_SCOPE_VIOLATION")
plugins {
id(ThunderbirdPlugins.Library.jvm)
alias(libs.plugins.android.lint)
}
dependencies {
api(projects.app.autodiscovery.api)
compileOnly(libs.xmlpull)
implementation(libs.okhttp)
testImplementation(libs.kxml2)
testImplementation(libs.okhttp.mockwebserver)
}

View file

@ -0,0 +1,28 @@
package com.fsck.k9.autodiscovery.thunderbird
import com.fsck.k9.logging.Timber
import java.io.IOException
import java.io.InputStream
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
class ThunderbirdAutoconfigFetcher(private val okHttpClient: OkHttpClient) {
fun fetchAutoconfigFile(url: HttpUrl): InputStream? {
return try {
val request = Request.Builder().url(url).build()
val response = okHttpClient.newCall(request).execute()
if (response.isSuccessful) {
response.body?.byteStream()
} else {
null
}
} catch (e: IOException) {
Timber.d(e, "Error fetching URL: %s", url)
null
}
}
}

View file

@ -0,0 +1,102 @@
package com.fsck.k9.autodiscovery.thunderbird
import com.fsck.k9.autodiscovery.api.DiscoveredServerSettings
import com.fsck.k9.autodiscovery.api.DiscoveryResults
import com.fsck.k9.mail.AuthType
import com.fsck.k9.mail.ConnectionSecurity
import java.io.IOException
import java.io.InputStream
import java.io.InputStreamReader
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException
import org.xmlpull.v1.XmlPullParserFactory
/**
* Parser for Thunderbird's
* [Autoconfig file format](https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat)
*/
class ThunderbirdAutoconfigParser {
fun parseSettings(stream: InputStream, email: String): DiscoveryResults? {
val factory = XmlPullParserFactory.newInstance()
val xpp = factory.newPullParser()
xpp.setInput(InputStreamReader(stream))
val incomingServers = mutableListOf<DiscoveredServerSettings>()
val outgoingServers = mutableListOf<DiscoveredServerSettings>()
var eventType = xpp.eventType
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
when (xpp.name) {
"incomingServer" -> {
incomingServers += parseServer(xpp, "incomingServer", email)
}
"outgoingServer" -> {
outgoingServers += parseServer(xpp, "outgoingServer", email)
}
}
}
eventType = xpp.next()
}
return DiscoveryResults(incomingServers, outgoingServers)
}
private fun parseServer(xpp: XmlPullParser, nodeName: String, email: String): DiscoveredServerSettings {
val type = xpp.getAttributeValue(null, "type")
var host: String? = null
var username: String? = null
var port: Int? = null
var authType: AuthType? = null
var connectionSecurity: ConnectionSecurity? = null
var eventType = xpp.eventType
while (!(eventType == XmlPullParser.END_TAG && nodeName == xpp.name)) {
if (eventType == XmlPullParser.START_TAG) {
when (xpp.name) {
"hostname" -> {
host = getText(xpp)
}
"port" -> {
port = getText(xpp).toInt()
}
"username" -> {
username = getText(xpp).replace("%EMAILADDRESS%", email)
}
"authentication" -> {
if (authType == null) authType = parseAuthType(getText(xpp))
}
"socketType" -> {
connectionSecurity = parseSocketType(getText(xpp))
}
}
}
eventType = xpp.next()
}
return DiscoveredServerSettings(type, host!!, port!!, connectionSecurity!!, authType, username)
}
private fun parseAuthType(authentication: String): AuthType? {
return when (authentication) {
"password-cleartext" -> AuthType.PLAIN
"TLS-client-cert" -> AuthType.EXTERNAL
"secure" -> AuthType.CRAM_MD5
else -> null
}
}
private fun parseSocketType(socketType: String): ConnectionSecurity? {
return when (socketType) {
"plain" -> ConnectionSecurity.NONE
"SSL" -> ConnectionSecurity.SSL_TLS_REQUIRED
"STARTTLS" -> ConnectionSecurity.STARTTLS_REQUIRED
else -> null
}
}
@Throws(XmlPullParserException::class, IOException::class)
private fun getText(xpp: XmlPullParser): String {
val eventType = xpp.next()
return if (eventType != XmlPullParser.TEXT) "" else xpp.text
}
}

View file

@ -0,0 +1,47 @@
package com.fsck.k9.autodiscovery.thunderbird
import com.fsck.k9.helper.EmailHelper
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
class ThunderbirdAutoconfigUrlProvider {
fun getAutoconfigUrls(email: String): List<HttpUrl> {
val domain = EmailHelper.getDomainFromEmailAddress(email)
requireNotNull(domain) { "Couldn't extract domain from email address: $email" }
return listOf(
createProviderUrl(domain, email),
createDomainUrl(scheme = "https", domain),
createDomainUrl(scheme = "http", domain),
createIspDbUrl(domain)
)
}
private fun createProviderUrl(domain: String?, email: String): HttpUrl {
// https://autoconfig.{domain}/mail/config-v1.1.xml?emailaddress={email}
return HttpUrl.Builder()
.scheme("https")
.host("autoconfig.$domain")
.addEncodedPathSegments("mail/config-v1.1.xml")
.addQueryParameter("emailaddress", email)
.build()
}
private fun createDomainUrl(scheme: String, domain: String): HttpUrl {
// https://{domain}/.well-known/autoconfig/mail/config-v1.1.xml
// http://{domain}/.well-known/autoconfig/mail/config-v1.1.xml
return HttpUrl.Builder()
.scheme(scheme)
.host(domain)
.addEncodedPathSegments(".well-known/autoconfig/mail/config-v1.1.xml")
.build()
}
private fun createIspDbUrl(domain: String): HttpUrl {
// https://autoconfig.thunderbird.net/v1.1/{domain}
return "https://autoconfig.thunderbird.net/v1.1/".toHttpUrl()
.newBuilder()
.addPathSegment(domain)
.build()
}
}

View file

@ -0,0 +1,28 @@
package com.fsck.k9.autodiscovery.thunderbird
import com.fsck.k9.autodiscovery.api.ConnectionSettingsDiscovery
import com.fsck.k9.autodiscovery.api.DiscoveryResults
class ThunderbirdDiscovery(
private val urlProvider: ThunderbirdAutoconfigUrlProvider,
private val fetcher: ThunderbirdAutoconfigFetcher,
private val parser: ThunderbirdAutoconfigParser
) : ConnectionSettingsDiscovery {
override fun discover(email: String): DiscoveryResults? {
val autoconfigUrls = urlProvider.getAutoconfigUrls(email)
return autoconfigUrls
.asSequence()
.mapNotNull { autoconfigUrl ->
fetcher.fetchAutoconfigFile(autoconfigUrl)?.use { inputStream ->
parser.parseSettings(inputStream, email)
}
}
.firstOrNull { result ->
result.incoming.isNotEmpty() || result.outgoing.isNotEmpty()
}
}
override fun toString(): String = "Thunderbird autoconfig"
}

View file

@ -0,0 +1,44 @@
package com.fsck.k9.autodiscovery.thunderbird
import assertk.assertThat
import assertk.assertions.isEqualTo
import assertk.assertions.isNull
import kotlin.test.assertNotNull
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import org.junit.Test
class ThunderbirdAutoconfigFetcherTest {
private val fetcher = ThunderbirdAutoconfigFetcher(OkHttpClient.Builder().build())
@Test
fun shouldHandleNonexistentUrl() {
val nonExistentUrl =
"https://autoconfig.domain.invalid/mail/config-v1.1.xml?emailaddress=test%40domain.example".toHttpUrl()
val inputStream = fetcher.fetchAutoconfigFile(nonExistentUrl)
assertThat(inputStream).isNull()
}
@Test
fun shouldHandleEmptyResponse() {
val server = MockWebServer().apply {
this.enqueue(
MockResponse()
.setBody("")
.setResponseCode(204),
)
start()
}
val url = server.url("/empty/")
val inputStream = fetcher.fetchAutoconfigFile(url)
assertNotNull(inputStream) { inputStream ->
assertThat(inputStream.available()).isEqualTo(0)
}
}
}

View file

@ -0,0 +1,174 @@
package com.fsck.k9.autodiscovery.thunderbird
import assertk.assertThat
import assertk.assertions.isEqualTo
import assertk.assertions.isNotNull
import com.fsck.k9.autodiscovery.api.DiscoveredServerSettings
import com.fsck.k9.autodiscovery.api.DiscoveryResults
import com.fsck.k9.mail.AuthType
import com.fsck.k9.mail.ConnectionSecurity
import org.junit.Test
class ThunderbirdAutoconfigTest {
private val parser = ThunderbirdAutoconfigParser()
@Test
fun settingsExtract() {
val input =
"""
<?xml version="1.0"?>
<clientConfig version="1.1">
<emailProvider id="metacode.biz">
<domain>metacode.biz</domain>
<incomingServer type="imap">
<hostname>imap.googlemail.com</hostname>
<port>993</port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
<authentication>OAuth2</authentication>
<authentication>password-cleartext</authentication>
</incomingServer>
<outgoingServer type="smtp">
<hostname>smtp.googlemail.com</hostname>
<port>465</port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
<authentication>OAuth2</authentication>
<authentication>password-cleartext</authentication>
<addThisServer>true</addThisServer>
</outgoingServer>
</emailProvider>
</clientConfig>
""".trimIndent().byteInputStream()
val connectionSettings = parser.parseSettings(input, "test@metacode.biz")
assertThat(connectionSettings).isNotNull()
assertThat(connectionSettings!!.incoming).isNotNull()
assertThat(connectionSettings.outgoing).isNotNull()
with(connectionSettings.incoming.first()) {
assertThat(host).isEqualTo("imap.googlemail.com")
assertThat(port).isEqualTo(993)
assertThat(username).isEqualTo("test@metacode.biz")
}
with(connectionSettings.outgoing.first()) {
assertThat(host).isEqualTo("smtp.googlemail.com")
assertThat(port).isEqualTo(465)
assertThat(username).isEqualTo("test@metacode.biz")
}
}
@Test
fun multipleServers() {
val input =
"""
<?xml version="1.0"?>
<clientConfig version="1.1">
<emailProvider id="metacode.biz">
<domain>metacode.biz</domain>
<incomingServer type="imap">
<hostname>imap.googlemail.com</hostname>
<port>993</port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
<authentication>OAuth2</authentication>
<authentication>password-cleartext</authentication>
</incomingServer>
<outgoingServer type="smtp">
<hostname>first</hostname>
<port>465</port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
<authentication>OAuth2</authentication>
<authentication>password-cleartext</authentication>
<addThisServer>true</addThisServer>
</outgoingServer>
<outgoingServer type="smtp">
<hostname>second</hostname>
<port>465</port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
<authentication>OAuth2</authentication>
<authentication>password-cleartext</authentication>
<addThisServer>true</addThisServer>
</outgoingServer>
</emailProvider>
</clientConfig>
""".trimIndent().byteInputStream()
val discoveryResults = parser.parseSettings(input, "test@metacode.biz")
assertThat(discoveryResults).isNotNull()
assertThat(discoveryResults!!.outgoing).isNotNull()
with(discoveryResults.outgoing[0]) {
assertThat(host).isEqualTo("first")
assertThat(port).isEqualTo(465)
assertThat(username).isEqualTo("test@metacode.biz")
}
with(discoveryResults.outgoing[1]) {
assertThat(host).isEqualTo("second")
assertThat(port).isEqualTo(465)
assertThat(username).isEqualTo("test@metacode.biz")
}
}
@Test
fun invalidResponse() {
val input =
"""
<?xml version="1.0"?>
<clientConfig version="1.1">
<emailProvider id="metacode.biz">
<domain>metacode.biz</domain>
""".trimIndent().byteInputStream()
val connectionSettings = parser.parseSettings(input, "test@metacode.biz")
assertThat(connectionSettings).isEqualTo(DiscoveryResults(listOf(), listOf()))
}
@Test
fun incompleteConfiguration() {
val input =
"""
<?xml version="1.0"?>
<clientConfig version="1.1">
<emailProvider id="metacode.biz">
<domain>metacode.biz</domain>
<incomingServer type="imap">
<hostname>imap.googlemail.com</hostname>
<port>993</port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
<authentication>OAuth2</authentication>
<authentication>password-cleartext</authentication>
</incomingServer>
</emailProvider>
</clientConfig>
""".trimIndent().byteInputStream()
val connectionSettings = parser.parseSettings(input, "test@metacode.biz")
assertThat(connectionSettings).isEqualTo(
DiscoveryResults(
listOf(
DiscoveredServerSettings(
protocol = "imap",
host = "imap.googlemail.com",
port = 993,
security = ConnectionSecurity.SSL_TLS_REQUIRED,
authType = AuthType.PLAIN,
username = "test@metacode.biz"
)
),
listOf()
)
)
}
}

View file

@ -0,0 +1,21 @@
package com.fsck.k9.autodiscovery.thunderbird
import assertk.assertThat
import assertk.assertions.containsExactly
import org.junit.Test
class ThunderbirdAutoconfigUrlProviderTest {
private val urlProvider = ThunderbirdAutoconfigUrlProvider()
@Test
fun `getAutoconfigUrls with ASCII email address`() {
val autoconfigUrls = urlProvider.getAutoconfigUrls("test@domain.example")
assertThat(autoconfigUrls.map { it.toString() }).containsExactly(
"https://autoconfig.domain.example/mail/config-v1.1.xml?emailaddress=test%40domain.example",
"https://domain.example/.well-known/autoconfig/mail/config-v1.1.xml",
"http://domain.example/.well-known/autoconfig/mail/config-v1.1.xml",
"https://autoconfig.thunderbird.net/v1.1/domain.example"
)
}
}