diff --git a/CHANGES.md b/CHANGES.md
index 7d4678fe40..a92a0e6d09 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -13,6 +13,7 @@ Bugfix 🐛:
  - Url previews sometimes attached to wrong message (#2561)
  - Hiding membership events works the exact opposite (#2603)
  - Tapping drawer having more than 1 room in notifications gives "malformed link" error (#2605)
+ - Sent image not displayed when opened immediately after sending (#409)
 
 Translations 🗣:
  -
diff --git a/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt b/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt
index a51410165b..d73c64b087 100644
--- a/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt
+++ b/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt
@@ -38,6 +38,6 @@ class MyAppGlideModule : AppGlideModule() {
     override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
         registry.append(ImageContentRenderer.Data::class.java,
                 InputStream::class.java,
-                VectorGlideModelLoaderFactory(context.vectorComponent().activeSessionHolder()))
+                VectorGlideModelLoaderFactory(context, context.vectorComponent().activeSessionHolder()))
     }
 }
diff --git a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt
index 9a7cf1eb76..600ed0317e 100644
--- a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt
+++ b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt
@@ -16,6 +16,7 @@
 
 package im.vector.app.core.glide
 
+import android.content.Context
 import com.bumptech.glide.Priority
 import com.bumptech.glide.load.DataSource
 import com.bumptech.glide.load.Options
@@ -25,6 +26,8 @@ import com.bumptech.glide.load.model.ModelLoaderFactory
 import com.bumptech.glide.load.model.MultiModelLoaderFactory
 import com.bumptech.glide.signature.ObjectKey
 import im.vector.app.core.di.ActiveSessionHolder
+import im.vector.app.core.utils.isLocalFile
+import im.vector.app.core.utils.openInputStream
 import im.vector.app.features.media.ImageContentRenderer
 import okhttp3.OkHttpClient
 import org.matrix.android.sdk.api.MatrixCallback
@@ -33,11 +36,12 @@ import java.io.File
 import java.io.IOException
 import java.io.InputStream
 
-class VectorGlideModelLoaderFactory(private val activeSessionHolder: ActiveSessionHolder)
-    : ModelLoaderFactory<ImageContentRenderer.Data, InputStream> {
+class VectorGlideModelLoaderFactory(private val context: Context,
+                                    private val activeSessionHolder: ActiveSessionHolder
+) : ModelLoaderFactory<ImageContentRenderer.Data, InputStream> {
 
     override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<ImageContentRenderer.Data, InputStream> {
-        return VectorGlideModelLoader(activeSessionHolder)
+        return VectorGlideModelLoader(context, activeSessionHolder)
     }
 
     override fun teardown() {
@@ -45,7 +49,7 @@ class VectorGlideModelLoaderFactory(private val activeSessionHolder: ActiveSessi
     }
 }
 
-class VectorGlideModelLoader(private val activeSessionHolder: ActiveSessionHolder)
+class VectorGlideModelLoader(private val context: Context, private val activeSessionHolder: ActiveSessionHolder)
     : ModelLoader<ImageContentRenderer.Data, InputStream> {
     override fun handles(model: ImageContentRenderer.Data): Boolean {
         // Always handle
@@ -53,11 +57,12 @@ class VectorGlideModelLoader(private val activeSessionHolder: ActiveSessionHolde
     }
 
     override fun buildLoadData(model: ImageContentRenderer.Data, width: Int, height: Int, options: Options): ModelLoader.LoadData<InputStream>? {
-        return ModelLoader.LoadData(ObjectKey(model), VectorGlideDataFetcher(activeSessionHolder, model, width, height))
+        return ModelLoader.LoadData(ObjectKey(model), VectorGlideDataFetcher(context, activeSessionHolder, model, width, height))
     }
 }
 
-class VectorGlideDataFetcher(private val activeSessionHolder: ActiveSessionHolder,
+class VectorGlideDataFetcher(private val context: Context,
+                             private val activeSessionHolder: ActiveSessionHolder,
                              private val data: ImageContentRenderer.Data,
                              private val width: Int,
                              private val height: Int)
@@ -97,9 +102,10 @@ class VectorGlideDataFetcher(private val activeSessionHolder: ActiveSessionHolde
 
     override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
         Timber.v("Load data: $data")
-        if (data.isLocalFile && data.url != null) {
-            val initialFile = File(data.url)
-            callback.onDataReady(initialFile.inputStream())
+        if (data.url.isLocalFile(context)) {
+            data.url.openInputStream(context)?.use {
+                callback.onDataReady(it)
+            }
             return
         }
 //        val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver()
diff --git a/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt b/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt
index aa36dd0959..2be06c09a5 100644
--- a/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt
+++ b/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt
@@ -17,14 +17,28 @@
 package im.vector.app.core.utils
 
 import android.content.Context
+import android.net.Uri
+import androidx.documentfile.provider.DocumentFile
+import org.matrix.android.sdk.api.extensions.orFalse
 import timber.log.Timber
 import java.io.File
+import java.io.InputStream
 import java.util.Locale
 
 // Implementation should return true in case of success
 typealias ActionOnFile = (file: File) -> Boolean
 
-internal fun String?.isLocalFile() = this != null && File(this).exists()
+internal fun String?.isLocalFile(context: Context): Boolean {
+    return this?.let {
+        DocumentFile.fromSingleUri(context, Uri.parse(it))?.exists()
+    }.orFalse()
+}
+
+internal fun String?.openInputStream(context: Context): InputStream? {
+    return if (isLocalFile(context)) {
+        context.contentResolver.openInputStream(Uri.parse(this))
+    } else null
+}
 
 /* ==========================================================================================
  * Delete
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt
index a1e041b98f..3dea83032c 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt
@@ -16,6 +16,7 @@
 
 package im.vector.app.features.home.room.detail.timeline.factory
 
+import android.content.Context
 import android.text.SpannableStringBuilder
 import android.text.Spanned
 import android.text.TextPaint
@@ -94,6 +95,7 @@ import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
 import javax.inject.Inject
 
 class MessageItemFactory @Inject constructor(
+        private val context: Context,
         private val colorProvider: ColorProvider,
         private val dimensionConverter: DimensionConverter,
         private val timelineMediaSizeProvider: TimelineMediaSizeProvider,
@@ -205,7 +207,7 @@ class MessageItemFactory @Inject constructor(
         } ?: ""
         return MessageFileItem_()
                 .attributes(attributes)
-                .izLocalFile(fileUrl.isLocalFile())
+                .izLocalFile(fileUrl.isLocalFile(context))
                 .izDownloaded(session.fileService().isFileInCache(
                         fileUrl,
                         messageContent.getFileName(),
@@ -270,7 +272,7 @@ class MessageItemFactory @Inject constructor(
         return MessageFileItem_()
                 .attributes(attributes)
                 .leftGuideline(avatarSizeProvider.leftGuideline)
-                .izLocalFile(messageContent.getFileUrl().isLocalFile())
+                .izLocalFile(messageContent.getFileUrl().isLocalFile(context))
                 .izDownloaded(session.fileService().isFileInCache(messageContent))
                 .mxcUrl(mxcUrl)
                 .contentUploadStateTrackerBinder(contentUploadStateTrackerBinder)
@@ -305,7 +307,8 @@ class MessageItemFactory @Inject constructor(
                 height = messageContent.info?.height,
                 maxHeight = maxHeight,
                 width = messageContent.info?.width,
-                maxWidth = maxWidth
+                maxWidth = maxWidth,
+                allowNonMxcUrls = informationData.sendState.isSending()
         )
         return MessageImageVideoItem_()
                 .attributes(attributes)
@@ -343,7 +346,8 @@ class MessageItemFactory @Inject constructor(
                 height = messageContent.videoInfo?.height,
                 maxHeight = maxHeight,
                 width = messageContent.videoInfo?.width,
-                maxWidth = maxWidth
+                maxWidth = maxWidth,
+                allowNonMxcUrls = informationData.sendState.isSending()
         )
 
         val videoData = VideoContentRenderer.Data(
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt
index 98db0bc9b9..a8d5ed1631 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt
@@ -26,6 +26,7 @@ import com.airbnb.epoxy.EpoxyAttribute
 import com.airbnb.epoxy.EpoxyModelClass
 import im.vector.app.R
 import im.vector.app.core.glide.GlideApp
+import im.vector.app.core.utils.isLocalFile
 import im.vector.app.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
 import im.vector.app.features.media.ImageContentRenderer
 import org.matrix.android.sdk.api.session.room.send.SendState
@@ -55,7 +56,7 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
         super.bind(holder)
         imageContentRenderer.render(mediaData, mode, holder.imageView)
         if (!attributes.informationData.sendState.hasFailed()) {
-            contentUploadStateTrackerBinder.bind(attributes.informationData.eventId, mediaData.isLocalFile, holder.progressLayout)
+            contentUploadStateTrackerBinder.bind(attributes.informationData.eventId, mediaData.url.isLocalFile(holder.view.context), holder.progressLayout)
         } else {
             holder.progressLayout.isVisible = false
         }
diff --git a/vector/src/main/java/im/vector/app/features/media/ImageContentRenderer.kt b/vector/src/main/java/im/vector/app/features/media/ImageContentRenderer.kt
index 75c7912646..83da8aa542 100644
--- a/vector/src/main/java/im/vector/app/features/media/ImageContentRenderer.kt
+++ b/vector/src/main/java/im/vector/app/features/media/ImageContentRenderer.kt
@@ -16,6 +16,7 @@
 
 package im.vector.app.features.media
 
+import android.content.Context
 import android.graphics.drawable.Drawable
 import android.net.Uri
 import android.os.Parcelable
@@ -59,7 +60,8 @@ interface AttachmentData : Parcelable {
     val allowNonMxcUrls: Boolean
 }
 
-class ImageContentRenderer @Inject constructor(private val activeSessionHolder: ActiveSessionHolder,
+class ImageContentRenderer @Inject constructor(private val context: Context,
+                                               private val activeSessionHolder: ActiveSessionHolder,
                                                private val dimensionConverter: DimensionConverter) {
 
     @Parcelize
@@ -73,7 +75,6 @@ class ImageContentRenderer @Inject constructor(private val activeSessionHolder:
             val maxHeight: Int,
             val width: Int?,
             val maxWidth: Int,
-            val isLocalFile: Boolean = url.isLocalFile(),
             // If true will load non mxc url, be careful to set it only for images sent by you
             override val allowNonMxcUrls: Boolean = false
     ) : AttachmentData
@@ -291,7 +292,7 @@ class ImageContentRenderer @Inject constructor(private val activeSessionHolder:
 
     private fun resolveUrl(data: Data) =
             (activeSessionHolder.getActiveSession().contentUrlResolver().resolveFullSize(data.url)
-                    ?: data.url?.takeIf { data.isLocalFile && data.allowNonMxcUrls })
+                    ?: data.url?.takeIf { data.url.isLocalFile(context) && data.allowNonMxcUrls })
 
     private fun processSize(data: Data, mode: Mode): Size {
         val maxImageWidth = data.maxWidth
diff --git a/vector/src/main/java/im/vector/app/features/media/VideoContentRenderer.kt b/vector/src/main/java/im/vector/app/features/media/VideoContentRenderer.kt
index c771eece8f..46e1437268 100644
--- a/vector/src/main/java/im/vector/app/features/media/VideoContentRenderer.kt
+++ b/vector/src/main/java/im/vector/app/features/media/VideoContentRenderer.kt
@@ -16,6 +16,7 @@
 
 package im.vector.app.features.media
 
+import android.content.Context
 import android.widget.ImageView
 import android.widget.ProgressBar
 import android.widget.TextView
@@ -33,7 +34,8 @@ import java.io.File
 import java.net.URLEncoder
 import javax.inject.Inject
 
-class VideoContentRenderer @Inject constructor(private val activeSessionHolder: ActiveSessionHolder,
+class VideoContentRenderer @Inject constructor(private val context: Context,
+                                               private val activeSessionHolder: ActiveSessionHolder,
                                                private val errorFormatter: ErrorFormatter) {
 
     @Parcelize
@@ -63,7 +65,7 @@ class VideoContentRenderer @Inject constructor(private val activeSessionHolder:
                 loadingView.isVisible = false
                 errorView.isVisible = true
                 errorView.setText(R.string.unknown_error)
-            } else if (data.url.isLocalFile() && data.allowNonMxcUrls) {
+            } else if (data.url.isLocalFile(context) && data.allowNonMxcUrls) {
                 thumbnailView.isVisible = false
                 loadingView.isVisible = false
                 videoView.isVisible = true
@@ -98,7 +100,7 @@ class VideoContentRenderer @Inject constructor(private val activeSessionHolder:
             }
         } else {
             val resolvedUrl = contentUrlResolver.resolveFullSize(data.url)
-                    ?: data.url?.takeIf { data.url.isLocalFile() && data.allowNonMxcUrls }
+                    ?: data.url?.takeIf { data.url.isLocalFile(context) && data.allowNonMxcUrls }
 
             if (resolvedUrl == null) {
                 thumbnailView.isVisible = false