Repository: thunderbird/thunderbird-android (language: kotlin)

Issue:
Non-english folder names are displayed incorrectly
### Checklist

- [x] I have used the search function to see if someone else has already submitted the same bug report.
- [x] I will describe the problem with as much detail as possible.

### App

K-9 Mail

### App version

Manually builded from branch main from 23.05.2025

### Where did you get the app from?

Other

### Android version

Android 14 HIOS (stock rom)

### Device model

Tecno Spark 30 (KL6)

### Steps to reproduce

1. Open app
2. Create account
3. Open folder list (left menu)
4. See "?" symbols instead of Cyrillic characters in folder names

### Expected behavior

Correct folder names, like this:

![Image](https://github.com/user-attachments/assets/9f32f4e9-8e02-4b5a-9d51-9571e54dedef)

### Actual behavior

Signs "?" instead of Cyrillic characters in folder names.

![Image](https://github.com/user-attachments/assets/c82ec8a7-0c24-43b2-876c-60741d8f1826)

### Logs

[k9mail-logs.txt](https://github.com/user-attachments/files/20417577/k9mail-logs.txt)


Discussion hints:
Could you try to grab the logs at the time the login process occurs or let us know if your email server supports SMTPUTF8 ? What email provider are you using?

Does this work on Thunderbird for Android 10 and fail on main?
> your email server supports SMTPUTF8?

Yes. If you're interested, here's the `EHLO test` command output:
```
250-smtp.mail.ru
250-SIZE 73400320
250-8BITMIME
250-DSN
250-SMTPUTF8
250 AUTH PLAIN LOGIN XOAUTH2
```

> Could you try to grab the logs at the time the login process occurs

[logcat.txt](https://github.com/user-attachments/files/20445840/logcat.txt)

> What email provider are you using?

mail.ru

> Does this work on Thunderbird for Android 10 and fail on main?

K9-mail and Thunderbird 10.0 works well. Thunderbird from branch main have this bug. 

This bug also appears on other phones with different versions of Android. I tested: Huawei Y5 Lite 2018 (Android 8), Alcatel Onetouch Pop 3 (5) (Android 5.1).
Ah I was thinking this might be a regression from #9171 but it looks like we haven't merged that yet. Maybe you can try to narrow it down a bit? We have a beta build, and there are daily builds on https://ftp.mozilla.org/pub/thunderbird-mobile/android/nightly/2025/

I'll see if we can take a look at this soon.
> Maybe you can try to narrow it down a bit? 

In daily builds from May 12 there is this bug. And if you install a build that does not have this bug, log in to your account, install (upgrade an existing) a build that has this bug, the bug does not appear.
#9171 wouldn't be related to this.

I suspect that it's connected to something the mail.ru IMAP server does. That's a freemail service, right? Creating an account seems a little difficult for someone who doesn't know Russian. @ke46138 can you help me get an account there?
> can you help me get an account there?

Send me an email to ke46138@gmail.com and I will send you the login and password.

> I suspect that it's connected to something the mail.ru IMAP server does. 

I doubt. Gmail has the same problem.

> That's a freemail service, right?

Yes
I can reproduce this on Gmail by creating a folder on Thunderbird Desktop named "Исходящие" and then going to Thunderbird for Android.
Oh, cool, then it should be easy to reproduce. I'm charging a test device now and can start working on this once it's charged.
Have reproduced the problem and have a failing unit test. More tomorrow.

Pull request: Handle UTF8 strings sent using literal syntax
RFC 6855/9755 permits IMAP servers to send UTF8 in strings such as "this", but does not ban sending literals such as {4}
this
instead, and some servers do, and #8772 did not handle that.

Fixes #9212

Test command: ./gradlew :mail:protocols:imap:test --tests "com.fsck.k9.mail.store.imap.RealImapStoreTest" --tests "com.fsck.k9.mail.store.imap.ImapResponseParserTest" --tests "com.fsck.k9.mail.store.imap.ImapFolderFetcherTest" --tests "com.fsck.k9.mail.store.imap.RealImapConnectionTest" --tests "com.fsck.k9.mail.store.imap.RealImapFolderTest"

Fix patch:
diff --git a/backend/imap/src/main/java/com/fsck/k9/backend/imap/CommandRefreshFolderList.kt b/backend/imap/src/main/java/com/fsck/k9/backend/imap/CommandRefreshFolderList.kt
index 3a79960785d..f6f70b3e7bd 100644
--- a/backend/imap/src/main/java/com/fsck/k9/backend/imap/CommandRefreshFolderList.kt
+++ b/backend/imap/src/main/java/com/fsck/k9/backend/imap/CommandRefreshFolderList.kt
@@ -36,8 +36,8 @@ internal class CommandRefreshFolderList(
 }
 
 private fun List<FolderListItem>.toLegacyFolderList(): List<LegacyFolderListItem> {
-    return this.filterNot { it.oldServerId == null }
-        .map { LegacyFolderListItem(it.oldServerId!!, it.name, it.type) }
+    return this
+        .map { LegacyFolderListItem(it.serverId, it.name, it.type) }
 }
 
 private data class LegacyFolderListItem(
diff --git a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/FolderListItem.kt b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/FolderListItem.kt
index b0bc0154edc..ce2f0cb5f48 100644
--- a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/FolderListItem.kt
+++ b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/FolderListItem.kt
@@ -6,5 +6,4 @@ data class FolderListItem(
     val serverId: String,
     val name: String,
     val type: FolderType,
-    val oldServerId: String?,
 )
diff --git a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/FolderNameCodec.kt b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/FolderNameCodec.kt
index 9619f654ded..7862f112f59 100644
--- a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/FolderNameCodec.kt
+++ b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/FolderNameCodec.kt
@@ -8,8 +8,13 @@ import java.nio.charset.StandardCharsets
 internal class FolderNameCodec {
     private val modifiedUtf7Charset = CharsetProvider().charsetForName("X-RFC-3501")
     private val asciiCharset = StandardCharsets.US_ASCII
+    var acceptUtf8Encoding = false
 
     fun encode(folderName: String): String {
+        if (acceptUtf8Encoding) {
+            return folderName
+        }
+
         val byteBuffer = modifiedUtf7Charset.encode(folderName)
         val bytes = ByteArray(byteBuffer.limit())
         byteBuffer.get(bytes)
@@ -18,6 +23,10 @@ internal class FolderNameCodec {
     }
 
     fun decode(encodedFolderName: String): String {
+        if (acceptUtf8Encoding) {
+            return encodedFolderName
+        }
+
         val decoder = modifiedUtf7Charset.newDecoder().onMalformedInput(CodingErrorAction.REPORT)
         val byteBuffer = ByteBuffer.wrap(encodedFolderName.toByteArray(asciiCharset))
         val charBuffer = decoder.decode(byteBuffer)
diff --git a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/ImapConnection.kt b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/ImapConnection.kt
index 7d67b0fcf1c..d4ad3fdc92c 100644
--- a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/ImapConnection.kt
+++ b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/ImapConnection.kt
@@ -19,6 +19,8 @@ internal interface ImapConnection {
 
     fun close()
 
+    fun canSendUTF8QuotedStrings(): Boolean
+
     @Throws(IOException::class, MessagingException::class)
     fun hasCapability(capability: String): Boolean
 
diff --git a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/ImapFolderFetcher.kt b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/ImapFolderFetcher.kt
index 3c74ab8e9d8..4e036ced350 100644
--- a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/ImapFolderFetcher.kt
+++ b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/ImapFolderFetcher.kt
@@ -50,10 +50,9 @@ class ImapFolderFetcher internal constructor(
         return try {
             store.getFolders()
                 .asSequence()
-                .filterNot { it.oldServerId == null }
                 .map { folder ->
                     RemoteFolder(
-                        serverId = FolderServerId(folder.oldServerId!!),
+                        serverId = FolderServerId(folder.serverId),
                         displayName = folder.name,
                         type = folder.type,
                     )
diff --git a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/ImapResponseParser.java b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/ImapResponseParser.java
index f1077c20ceb..d77d504fcc7 100644
--- a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/ImapResponseParser.java
+++ b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/ImapResponseParser.java
@@ -22,14 +22,15 @@ class ImapResponseParser {
     private boolean utf8Accept;
     private FolderNameCodec folderNameCodec;
 
-    public ImapResponseParser(PeekableInputStream in) {
+    public ImapResponseParser(PeekableInputStream in, FolderNameCodec folderNameCodec) {
         this.inputStream = in;
         this.utf8Accept = false;
-        this.folderNameCodec = new FolderNameCodec();
+        this.folderNameCodec = folderNameCodec;
     }
 
     public void setUtf8Accepted(final boolean yes) {
         utf8Accept = yes;
+        folderNameCodec.setAcceptUtf8Encoding(yes);
     }
 
     public ImapResponse readResponse() throws IOException {
@@ -417,7 +418,7 @@ private Object parseLiteral() throws IOException {
             read += count;
         }
 
-        return new String(data, "US-ASCII");
+        return new String(data, "UTF8");
     }
 
     private String parseQuoted() throws IOException {
diff --git a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapConnection.kt b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapConnection.kt
index 4923b0ed8f6..ccf7a3ae953 100644
--- a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapConnection.kt
+++ b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapConnection.kt
@@ -45,6 +45,7 @@ internal class RealImapConnection(
     private val settings: ImapSettings,
     private val socketFactory: TrustedSocketFactory,
     private val oauthTokenProvider: OAuth2TokenProvider?,
+    private val folderNameCodec: FolderNameCodec,
     override val connectionGeneration: Int,
     private val socketConnectTimeout: Int = SOCKET_CONNECT_TIMEOUT,
     private val socketReadTimeout: Int = SOCKET_READ_TIMEOUT,
@@ -206,7 +207,7 @@ internal class RealImapConnection(
 
     private fun setUpStreamsAndParser(input: InputStream, output: OutputStream) {
         inputStream = PeekableInputStream(BufferedInputStream(input, BUFFER_SIZE))
-        responseParser = ImapResponseParser(inputStream)
+        responseParser = ImapResponseParser(inputStream, folderNameCodec)
         imapOutputStream = BufferedOutputStream(output, BUFFER_SIZE)
     }
 
@@ -676,6 +677,10 @@ internal class RealImapConnection(
         return isListResponse && hierarchyDelimiterValid
     }
 
+    override fun canSendUTF8QuotedStrings(): Boolean {
+        return isUtf8AcceptCapable // later: or IMAP4Rev2 is enabled
+    }
+
     override fun hasCapability(capability: String): Boolean {
         if (!open) {
             open()
diff --git a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapFolder.kt b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapFolder.kt
index 01dcaf26a65..f0e2cb8378a 100644
--- a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapFolder.kt
+++ b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapFolder.kt
@@ -98,11 +98,7 @@ internal class RealImapFolder(
     @get:Throws(MessagingException::class)
     private val encodedName: String
         get() {
-            return if (connection?.isUtf8AcceptCapable == true) {
-                prefixedName
-            } else {
-                folderNameCodec.encode(prefixedName)
-            }
+            return folderNameCodec.encode(prefixedName)
         }
 
     @Throws(MessagingException::class, IOException::class)
@@ -311,11 +307,7 @@ internal class RealImapFolder(
 
         val uids = messages.map { it.uid.toLong() }.toSet()
         val encodedDestinationFolderName =
-            if (connection!!.isUtf8AcceptCapable) {
-                folder.prefixedName
-            } else {
-                folderNameCodec.encode(folder.prefixedName)
-            }
+            folderNameCodec.encode(folder.prefixedName)
         val escapedDestinationFolderName = ImapUtility.encodeString(encodedDestinationFolderName)
 
         return try {
@@ -351,11 +343,7 @@ internal class RealImapFolder(
 
         val uids = messages.map { it.uid.toLong() }.toSet()
         val encodedDestinationFolderName =
-            if (connection!!.isUtf8AcceptCapable) {
-                folder.prefixedName
-            } else {
-                folderNameCodec.encode(folder.prefixedName)
-            }
+            folderNameCodec.encode(folder.prefixedName)
         val escapedDestinationFolderName = ImapUtility.encodeString(encodedDestinationFolderName)
 
         return try {
diff --git a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapStore.kt b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapStore.kt
index 8e2e7bb3950..ca36081bc97 100644
--- a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapStore.kt
+++ b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapStore.kt
@@ -18,6 +18,8 @@ import java.util.Deque
 import java.util.LinkedList
 import net.thunderbird.core.logging.legacy.Log
 
+private const val LAST_ASCII_CODE = 127
+
 internal open class RealImapStore(
     private val serverSettings: ServerSettings,
     override val config: ImapStoreConfig,
@@ -154,7 +156,6 @@ internal open class RealImapStore(
             }
 
             val name = getFolderDisplayName(serverId)
-            val oldServerId = getOldServerId(serverId)
 
             val type = when {
                 listResponse.hasAttribute("\\Archive") -> FolderType.ARCHIVE
@@ -168,19 +169,23 @@ internal open class RealImapStore(
 
             val existingItem = folderMap[serverId]
             if (existingItem == null || existingItem.type == FolderType.REGULAR) {
-                folderMap[serverId] = FolderListItem(serverId, name, type, oldServerId)
+                folderMap[serverId] = FolderListItem(serverId, name, type)
             }
         }
 
         return buildList {
-            add(FolderListItem(RealImapFolder.INBOX, RealImapFolder.INBOX, FolderType.INBOX, RealImapFolder.INBOX))
+            add(FolderListItem(RealImapFolder.INBOX, RealImapFolder.INBOX, FolderType.INBOX))
             addAll(folderMap.values)
         }
     }
 
     private fun getFolderDisplayName(serverId: String): String {
         val decodedFolderName = try {
-            folderNameCodec.decode(serverId)
+            if (serverId.all { it.code <= LAST_ASCII_CODE }) {
+                folderNameCodec.decode(serverId)
+            } else {
+                serverId
+            }
         } catch (e: CharacterCodingException) {
             Log.w(e, "Folder name not correctly encoded with the UTF-7 variant as defined by RFC 3501: %s", serverId)
             serverId
@@ -190,17 +195,6 @@ internal open class RealImapStore(
         return folderNameWithoutPrefix ?: decodedFolderName
     }
 
-    private fun getOldServerId(serverId: String): String? {
-        val decodedFolderName = try {
-            folderNameCodec.decode(serverId)
-        } catch (e: CharacterCodingException) {
-            // Previous versions of K-9 Mail ignored folders with invalid UTF-7 encoding
-            return null
-        }
-
-        return removePrefixFromFolderName(decodedFolderName)
-    }
-
     private fun removePrefixFromFolderName(folderName: String): String? {
         val prefix = getCombinedPrefix()
         val prefixLength = prefix.length
@@ -287,6 +281,7 @@ internal open class RealImapStore(
             StoreImapSettings(),
             trustedSocketFactory,
             oauthTokenProvider,
+            folderNameCodec,
             connectionGeneration,
         )
     }


Test patch:
diff --git a/backend/imap/src/test/java/com/fsck/k9/backend/imap/TestImapStore.kt b/backend/imap/src/test/java/com/fsck/k9/backend/imap/TestImapStore.kt
index acd95b9c483..098cb8e909c 100644
--- a/backend/imap/src/test/java/com/fsck/k9/backend/imap/TestImapStore.kt
+++ b/backend/imap/src/test/java/com/fsck/k9/backend/imap/TestImapStore.kt
@@ -33,7 +33,6 @@ class TestImapStore : ImapStore {
                 serverId = folder.serverId,
                 name = "irrelevant",
                 type = FolderType.REGULAR,
-                oldServerId = null,
             )
         }
     }
diff --git a/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/ImapFolderFetcherTest.kt b/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/ImapFolderFetcherTest.kt
index 8830ebc0eb4..48fa58dc53e 100644
--- a/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/ImapFolderFetcherTest.kt
+++ b/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/ImapFolderFetcherTest.kt
@@ -60,49 +60,41 @@ class ImapFolderFetcherTest {
                     serverId = "INBOX",
                     name = "INBOX",
                     type = FolderType.INBOX,
-                    oldServerId = "INBOX",
                 ),
                 FolderListItem(
                     serverId = "[Gmail]/All Mail",
                     name = "[Gmail]/All Mail",
                     type = FolderType.ARCHIVE,
-                    oldServerId = "[Gmail]/All Mail",
                 ),
                 FolderListItem(
                     serverId = "[Gmail]/Drafts",
                     name = "[Gmail]/Drafts",
                     type = FolderType.DRAFTS,
-                    oldServerId = "[Gmail]/Drafts",
                 ),
                 FolderListItem(
                     serverId = "[Gmail]/Important",
                     name = "[Gmail]/Important",
                     type = FolderType.REGULAR,
-                    oldServerId = "[Gmail]/Important",
                 ),
                 FolderListItem(
                     serverId = "[Gmail]/Sent Mail",
                     name = "[Gmail]/Sent Mail",
                     type = FolderType.SENT,
-                    oldServerId = "[Gmail]/Sent Mail",
                 ),
                 FolderListItem(
                     serverId = "[Gmail]/Spam",
                     name = "[Gmail]/Spam",
                     type = FolderType.SPAM,
-                    oldServerId = "[Gmail]/Spam",
                 ),
                 FolderListItem(
                     serverId = "[Gmail]/Starred",
                     name = "[Gmail]/Starred",
                     type = FolderType.REGULAR,
-                    oldServerId = "[Gmail]/Starred",
                 ),
                 FolderListItem(
                     serverId = "[Gmail]/Trash",
                     name = "[Gmail]/Trash",
                     type = FolderType.TRASH,
-                    oldServerId = "[Gmail]/Trash",
                 ),
             )
         }
@@ -154,38 +146,6 @@ class ImapFolderFetcherTest {
         assertThat(fakeImapStore.hasOpenConnections).isFalse()
     }
 
-    @Test
-    fun `folder without oldServerId should be ignored`() {
-        fakeImapStore.getFoldersAction = {
-            listOf(
-                FolderListItem(
-                    serverId = "ünicode",
-                    name = "ünicode",
-                    type = FolderType.REGULAR,
-                    oldServerId = null,
-                ),
-                FolderListItem(
-                    serverId = "INBOX",
-                    name = "INBOX",
-                    type = FolderType.INBOX,
-                    oldServerId = "INBOX",
-                ),
-            )
-        }
-
-        val folders = folderFetcher.getFolders(serverSettings, authStateStorage = null)
-
-        assertThat(folders).containsExactly(
-            RemoteFolder(
-                serverId = FolderServerId("INBOX"),
-                displayName = "INBOX",
-                type = FolderType.INBOX,
-            ),
-        )
-
-        assertThat(fakeImapStore.hasOpenConnections).isFalse()
-    }
-
     @Test
     fun `authentication error should throw FolderFetcherException with server message`() {
         fakeImapStore.getFoldersAction = {
diff --git a/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/ImapResponseHelper.java b/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/ImapResponseHelper.java
index 5eb48ecc67d..cd639e6a9d3 100644
--- a/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/ImapResponseHelper.java
+++ b/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/ImapResponseHelper.java
@@ -21,9 +21,14 @@ public static List<ImapResponse> createImapResponseList(String... responses) thr
     }
 
     public static ImapResponse createImapResponse(String response) throws IOException {
+        return createImapResponse(response, false);
+    }
+
+    public static ImapResponse createImapResponse(String response, boolean utf8) throws IOException {
         String input = response + "\r\n";
         PeekableInputStream inputStream = new PeekableInputStream(new ByteArrayInputStream(input.getBytes()));
-        ImapResponseParser parser = new ImapResponseParser(inputStream);
+        ImapResponseParser parser = new ImapResponseParser(inputStream, new FolderNameCodec());
+        parser.setUtf8Accepted(utf8);
 
         return parser.readResponse();
     }
diff --git a/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/ImapResponseParserTest.kt b/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/ImapResponseParserTest.kt
index b17042a3688..1963e86b836 100644
--- a/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/ImapResponseParserTest.kt
+++ b/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/ImapResponseParserTest.kt
@@ -471,6 +471,18 @@ class ImapResponseParserTest {
         assertThatAllInputWasConsumed()
     }
 
+    @Test
+    fun `readResponse() with LIST response containing folder name with literal UTF8`() {
+        val parser = createParserWithResponses("""* LIST (\hasnochildren) "/" {18}""" + "\r\nИсходящие")
+
+        parser.setUtf8Accepted(true)
+        val response = parser.readResponse()
+
+        assertThat(response).hasSize(4)
+        assertThat(response).index(3).isEqualTo("Исходящие")
+        assertThatAllInputWasConsumed()
+    }
+
     @Test
     fun `readResponse() with LIST response containing folder name with parentheses should throw`() {
         val parser = createParserWithResponses("""* LIST (\NoInferiors) "/" Root/Folder/Subfolder()""")
@@ -595,7 +607,7 @@ class ImapResponseParserTest {
         val byteArrayInputStream = ByteArrayInputStream(response.toByteArray(Charsets.UTF_8))
         peekableInputStream = PeekableInputStream(byteArrayInputStream)
 
-        return ImapResponseParser(peekableInputStream)
+        return ImapResponseParser(peekableInputStream, FolderNameCodec())
     }
 
     private fun assertThatAllInputWasConsumed() {
diff --git a/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/RealImapConnectionTest.kt b/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/RealImapConnectionTest.kt
index 39daedb6064..c34fdd6c2f4 100644
--- a/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/RealImapConnectionTest.kt
+++ b/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/RealImapConnectionTest.kt
@@ -1185,6 +1185,7 @@ class RealImapConnectionTest {
             settings,
             socketFactory,
             oAuth2TokenProvider,
+            FolderNameCodec(),
             connectionGeneration,
             SOCKET_CONNECT_TIMEOUT,
             SOCKET_READ_TIMEOUT,
diff --git a/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/RealImapFolderTest.kt b/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/RealImapFolderTest.kt
index 6588cc462dd..6731f1406e0 100644
--- a/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/RealImapFolderTest.kt
+++ b/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/RealImapFolderTest.kt
@@ -379,6 +379,25 @@ class RealImapFolderTest {
         assertThat(uidMapping).isNotNull().containsOnly("1" to "101")
     }
 
+    @Test
+    fun `moveMessages() with MOVE and UTF8=ACCEPT extensions`() {
+        val folderNameCodec = FolderNameCodec()
+        folderNameCodec.acceptUtf8Encoding = true
+        val sourceFolder = RealImapFolder(internalImapStore, testConnectionManager, "Folder", folderNameCodec)
+        prepareImapFolderForOpen(OpenMode.READ_WRITE)
+        imapConnection.stub {
+            on { hasCapability(Capabilities.MOVE) } doReturn true
+        }
+        val destinationFolder = createFolder("la vache dit møø")
+        val messages = listOf(createImapMessage("1"))
+        setupMoveResponses("x OK [COPYUID 23 1 101] Success")
+        sourceFolder.open(OpenMode.READ_WRITE)
+
+        val uidMapping = sourceFolder.moveMessages(messages, destinationFolder)
+
+        assertCommandWithIdsIssued("UID MOVE 1 \"la vache dit møø\"")
+    }
+
     @Test
     fun moveMessages_shouldCopyMessages() {
         val sourceFolder = createFolder("Folder")
diff --git a/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/RealImapStoreTest.kt b/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/RealImapStoreTest.kt
index c46c6dd95b6..a154763c2e1 100644
--- a/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/RealImapStoreTest.kt
+++ b/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/RealImapStoreTest.kt
@@ -116,6 +116,23 @@ class RealImapStoreTest {
         verify(imapConnection).executeSimpleCommand("""LIST "" "*"""")
     }
 
+    @Test
+    fun `getFolder() should not corrupt UTF8 folder names`() {
+        val imapStore = createTestImapStore(isSubscribedFoldersOnly = false)
+        val imapConnection = createMockConnection().stub {
+            on { executeSimpleCommand("""LIST "" "*"""") } doReturn listOf(
+                createImapResponse("""* LIST () "." "Chèvre"""", true),
+                createImapResponse("6 OK Success"),
+            )
+        }
+        imapStore.enqueueImapConnection(imapConnection)
+
+        val folders = imapStore.getFolders()
+
+        assertThat(folders).isNotNull()
+        assertThat(folders.map { it.name }).containsExactly("INBOX", "Chèvre")
+    }
+
     @Test
     fun `getFolders() should ignore NoSelect entries`() {
         val imapStore = createTestImapStore(isSubscribedFoldersOnly = false)
@@ -218,7 +235,6 @@ class RealImapStoreTest {
         assertThat(folders).isNotNull()
         assertThat(folders.map { it.serverId }).containsExactly("INBOX", "INBOX.FolderOne", "INBOX.FolderTwo")
         assertThat(folders.map { it.name }).containsExactly("INBOX", "FolderOne", "FolderTwo")
-        assertThat(folders.map { it.oldServerId }).containsExactly("INBOX", "FolderOne", "FolderTwo")
     }
 
     @Test
@@ -239,7 +255,6 @@ class RealImapStoreTest {
         assertThat(folders).isNotNull()
         assertThat(folders.map { it.serverId }).containsExactly("INBOX", "INBOX.FolderOne", "FolderTwo")
         assertThat(folders.map { it.name }).containsExactly("INBOX", "FolderOne", "FolderTwo")
-        assertThat(folders.mapNotNull { it.oldServerId }).containsExactly("INBOX", "FolderOne")
     }
 
     @Test
diff --git a/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/TestImapConnection.kt b/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/TestImapConnection.kt
index d9996ddf039..a43ea6df71f 100644
--- a/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/TestImapConnection.kt
+++ b/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/TestImapConnection.kt
@@ -38,6 +38,10 @@ internal open class TestImapConnection(val timeout: Long, override val connectio
         isConnected = false
     }
 
+    override fun canSendUTF8QuotedStrings(): Boolean {
+        return false // to be mocked where appropriate
+    }
+
     override fun hasCapability(capability: String): Boolean {
         throw UnsupportedOperationException("not implemented")
     }