diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt
index 9a97f643c..b37ba9d7d 100644
--- a/buildSrc/src/main/kotlin/Versions.kt
+++ b/buildSrc/src/main/kotlin/Versions.kt
@@ -45,6 +45,7 @@ fun ktor(id: String, version: String = Versions.ktor) = "io.ktor:ktor-$id:$versi
 
 
 val `kotlinx-coroutines-core` = kotlinx("coroutines-core", Versions.coroutines)
+val `kotlinx-coroutines-jdk8` = kotlinx("coroutines-jdk8", Versions.coroutines)
 val `kotlinx-serialization-core` = kotlinx("serialization-core", Versions.serialization)
 val `kotlinx-serialization-json` = kotlinx("serialization-json", Versions.serialization)
 val `kotlinx-serialization-protobuf` = kotlinx("serialization-protobuf", Versions.serialization)
diff --git a/mirai-core-api/build.gradle.kts b/mirai-core-api/build.gradle.kts
index 896c36e0e..29ca771f7 100644
--- a/mirai-core-api/build.gradle.kts
+++ b/mirai-core-api/build.gradle.kts
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2020 Mamoe Technologies and contributors.
+ * Copyright 2019-2021 Mamoe Technologies and contributors.
  *
  *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -78,6 +78,7 @@ kotlin {
                 api1(`kotlinx-io-jvm`)
                 api1(`kotlinx-coroutines-io-jvm`)
                 api(`kotlinx-coroutines-core`)
+               // api(`kotlinx-coroutines-jdk8`)
 
                 implementation1(`kotlinx-atomicfu`)
 
diff --git a/mirai-core-api/src/commonMain/kotlin/message/MessageReceipt.kt b/mirai-core-api/src/commonMain/kotlin/message/MessageReceipt.kt
index 5d3bccef2..2a3d531b9 100644
--- a/mirai-core-api/src/commonMain/kotlin/message/MessageReceipt.kt
+++ b/mirai-core-api/src/commonMain/kotlin/message/MessageReceipt.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2020 Mamoe Technologies and contributors.
+ * Copyright 2019-2021 Mamoe Technologies and contributors.
  *
  *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -11,12 +11,12 @@
 
 package net.mamoe.mirai.message
 
-import kotlinx.coroutines.Deferred
 import net.mamoe.kjbb.JvmBlockingBridge
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.IMirai
 import net.mamoe.mirai.Mirai
 import net.mamoe.mirai.contact.*
+import net.mamoe.mirai.message.action.AsyncRecallResult
 import net.mamoe.mirai.message.data.*
 import net.mamoe.mirai.message.data.MessageSource.Key.quote
 import net.mamoe.mirai.message.data.MessageSource.Key.recallIn
@@ -70,7 +70,7 @@ public open class MessageReceipt<out C : Contact> @MiraiInternalApi constructor(
      * @see IMirai.recallMessage
      */
     @Suppress("DeferredIsResult")
-    public fun recallIn(millis: Long): Deferred<Unit> = this.source.recallIn(millis)
+    public fun recallIn(millis: Long): AsyncRecallResult = this.source.recallIn(millis)
 
     /**
      * 引用这条消息.
diff --git a/mirai-core-api/src/commonMain/kotlin/message/action/AsyncRecallResult.kt b/mirai-core-api/src/commonMain/kotlin/message/action/AsyncRecallResult.kt
new file mode 100644
index 000000000..b3afffb69
--- /dev/null
+++ b/mirai-core-api/src/commonMain/kotlin/message/action/AsyncRecallResult.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2020 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/master/LICENSE
+ */
+
+@file:Suppress("MemberVisibilityCanBePrivate", "unused")
+
+package net.mamoe.mirai.message.action
+
+import kotlinx.coroutines.*
+import net.mamoe.kjbb.JvmBlockingBridge
+import net.mamoe.mirai.message.data.MessageSource
+import net.mamoe.mirai.message.data.MessageSource.Key.recallIn
+import java.util.concurrent.CompletableFuture
+
+/**
+ * [MessageSource.recallIn] 的结果.
+ *
+ * @see MessageSource.recallIn
+ */
+public class AsyncRecallResult internal constructor(
+    /**
+     * 撤回时产生的异常. Kotlin [Deferred] API.
+     */
+    public val exception: Deferred<Throwable?>,
+) {
+    /**
+     * 撤回时产生的异常. Java [CompletableFuture] API.
+     */
+    public val exceptionFuture: CompletableFuture<Throwable?> by lazy { exception.asCompletableFuture() }
+
+    /**
+     * 撤回是否成功. Kotlin [Deferred] API.
+     */
+    public val isSuccess: Deferred<Boolean> by lazy {
+        GlobalScope.async {
+            kotlin.runCatching { exception.await() == null }.getOrElse { false }
+        }
+    }
+
+    /**
+     * 撤回是否成功. Java [CompletableFuture] API.
+     */
+    public val isSuccessFuture: CompletableFuture<Boolean> by lazy { isSuccess.asCompletableFuture() }
+
+    /**
+     * 等待撤回完成, 返回撤回时产生的异常.
+     */
+    @JvmBlockingBridge
+    public suspend fun awaitException(): Throwable? {
+        return exception.await()
+    }
+
+    /**
+     * 等待撤回完成, 返回撤回的结果.
+     */
+    @JvmBlockingBridge
+    public suspend fun awaitIsSuccess(): Boolean {
+        return isSuccess.await()
+    }
+}
+
+
+// copied from kotlinx-coroutines-jdk8
+private fun <T> Deferred<T>.asCompletableFuture(): CompletableFuture<T> {
+    val future = CompletableFuture<T>()
+    setupCancellation(future)
+    invokeOnCompletion {
+        @OptIn(ExperimentalCoroutinesApi::class)
+        try {
+            future.complete(getCompleted())
+        } catch (t: Throwable) {
+            future.completeExceptionally(t)
+        }
+    }
+    return future
+}
+
+// copied from kotlinx-coroutines-jdk8
+private fun Job.setupCancellation(future: CompletableFuture<*>) {
+    future.whenComplete { _, exception ->
+        cancel(exception?.let {
+            it as? CancellationException ?: CancellationException("CompletableFuture was completed exceptionally", it)
+        })
+    }
+}
diff --git a/mirai-core-api/src/commonMain/kotlin/message/data/MessageSource.kt b/mirai-core-api/src/commonMain/kotlin/message/data/MessageSource.kt
index d5de174ee..f56b9f40e 100644
--- a/mirai-core-api/src/commonMain/kotlin/message/data/MessageSource.kt
+++ b/mirai-core-api/src/commonMain/kotlin/message/data/MessageSource.kt
@@ -25,6 +25,7 @@ import net.mamoe.mirai.contact.*
 import net.mamoe.mirai.event.events.MessageEvent
 import net.mamoe.mirai.internal.message.MessageSourceSerializerImpl
 import net.mamoe.mirai.message.MessageReceipt
+import net.mamoe.mirai.message.action.AsyncRecallResult
 import net.mamoe.mirai.message.data.MessageSource.Key.quote
 import net.mamoe.mirai.message.data.MessageSource.Key.recall
 import net.mamoe.mirai.utils.LazyProperty
@@ -199,20 +200,26 @@ public sealed class MessageSource : Message, MessageMetadata, ConstrainSingle {
          */
         @JvmStatic
         @Suppress("DeferredIsResult")
-        public fun MessageChain.recallIn(millis: Long): Deferred<Unit> = this.source.recallIn(millis)
+        public fun MessageChain.recallIn(millis: Long): AsyncRecallResult = this.source.recallIn(millis)
 
         /**
          * 在一段时间后撤回这条消息.
          *
+         * @return 返回撤回的结果 [Deferred]. [Deferred.await] 返回 `null` 表示成功执行
          * @see IMirai.recallMessage
          */
         @JvmStatic
         @Suppress("DeferredIsResult")
-        public fun MessageSource.recallIn(millis: Long): Deferred<Unit> {
-            return bot.async {
-                delay(millis)
-                Mirai.recallMessage(bot, this@recallIn)
-            }
+        public fun MessageSource.recallIn(millis: Long): AsyncRecallResult {
+            return AsyncRecallResult(bot.async {
+                try {
+                    delay(millis)
+                    Mirai.recallMessage(bot, this@recallIn)
+                    null
+                } catch (e: Throwable) {
+                    e
+                }
+            })
         }
 
         /**