diff --git a/src/bot.ts b/src/bot.ts
index 0990a3e23e05b4ea9ce19f5146bd47e9b083714f..b3759472e3063013da571b6691cda50e3aee65be 100644
--- a/src/bot.ts
+++ b/src/bot.ts
@@ -50,6 +50,7 @@ const MATRIX_ICON_URL = "https://matrix.org/_matrix/media/r0/download/matrix.org
 class ChannelLookupResult {
     public channel: Discord.TextChannel;
     public botUser: boolean;
+    public canSendEmbeds: boolean;
 }
 
 interface IThirdPartyLookupField {
@@ -362,6 +363,7 @@ export class DiscordBot {
                 const lookupResult = new ChannelLookupResult();
                 lookupResult.channel = channel as Discord.TextChannel;
                 lookupResult.botUser = this.bot.user.id === client.user.id;
+                lookupResult.canSendEmbeds = client.user.bot; // only bots can send embeds
                 return lookupResult;
             }
             throw new Error(`Channel "${room}" not found`);
@@ -414,18 +416,55 @@ export class DiscordBot {
         }
         try {
             this.channelLock.set(chan.id);
-            if (!botUser) {
-                // NOTE: Don't send replies to discord if we are a puppet.
+            if (!roomLookup.canSendEmbeds) {
+                // NOTE: Don't send replies to discord if we are a puppet user.
+                let addText = "";
+                if (embedSet.replyEmbed) {
+                    for (const line of embedSet.replyEmbed.description!.split("\n")) {
+                        addText += "\n> " + line;
+                    }
+                }
+                msg = await chan.send(embed.description + addText, opts);
+            } else if (!botUser) {
+                if (embedSet.imageEmbed || embedSet.replyEmbed) {
+                    let sendEmbed = new Discord.RichEmbed();
+                    if (embedSet.imageEmbed) {
+                        if (!embedSet.replyEmbed) {
+                            sendEmbed = embedSet.imageEmbed;
+                        } else {
+                            sendEmbed.setImage(embedSet.imageEmbed.image!.url);
+                        }
+                    }
+                    if (embedSet.replyEmbed) {
+                        if (!embedSet.imageEmbed) {
+                            sendEmbed = embedSet.replyEmbed;
+                        } else {
+                            sendEmbed.addField("Replying to", embedSet.replyEmbed!.author!.name);
+                            sendEmbed.addField("Reply text", embedSet.replyEmbed.description);
+                        }
+                    }
+                    opts.embed = sendEmbed;
+                }
                 msg = await chan.send(embed.description, opts);
             } else if (hook) {
                 MetricPeg.get.remoteCall("hook.send");
+                const embeds: Discord.RichEmbed[] = [];
+                if (embedSet.imageEmbed) {
+                    embeds.push(embedSet.imageEmbed);
+                }
+                if (embedSet.replyEmbed) {
+                    embeds.push(embedSet.replyEmbed);
+                }
                 msg = await hook.send(embed.description, {
                     avatarURL: embed!.author!.icon_url,
-                    embeds: embedSet.replyEmbed ? [embedSet.replyEmbed] : undefined,
+                    embeds,
                     files: opts.file ? [opts.file] : undefined,
                     username: embed!.author!.name,
                 } as Discord.WebhookMessageOptions);
             } else {
+                if (embedSet.imageEmbed) {
+                    embed.setImage(embedSet.imageEmbed.image!.url);
+                }
                 if (embedSet.replyEmbed) {
                     embed.addField("Replying to", embedSet.replyEmbed!.author!.name);
                     embed.addField("Reply text", embedSet.replyEmbed.description);
diff --git a/src/matrixeventprocessor.ts b/src/matrixeventprocessor.ts
index 762380ee024d3afa2b1cf140e0b0db4d4b85a849..26f94ee0c6df7ba3c37c9e2c91e4aa94239920d5 100644
--- a/src/matrixeventprocessor.ts
+++ b/src/matrixeventprocessor.ts
@@ -54,6 +54,7 @@ export class MatrixEventProcessorOpts {
 export interface IMatrixEventProcessorResult {
     messageEmbed: Discord.RichEmbed;
     replyEmbed?: Discord.RichEmbed;
+    imageEmbed?: Discord.RichEmbed;
 }
 
 export class MatrixEventProcessor {
@@ -170,11 +171,13 @@ export class MatrixEventProcessor {
 
         const embedSet = await this.EventToEmbed(event, chan);
         const opts: Discord.MessageOptions = {};
-        const file = await this.HandleAttachment(event, mxClient);
+        const file = await this.HandleAttachment(event, mxClient, roomLookup.canSendEmbeds);
         if (typeof(file) === "string") {
             embedSet.messageEmbed.description += " " + file;
+        } else if ((file as Discord.FileOptions).name && (file as Discord.FileOptions).attachment) {
+            opts.file = file as Discord.FileOptions;
         } else {
-            opts.file = file;
+            embedSet.imageEmbed = file as Discord.RichEmbed;
         }
 
         await this.discord.send(embedSet, opts, roomLookup, event);
@@ -284,7 +287,11 @@ export class MatrixEventProcessor {
         };
     }
 
-    public async HandleAttachment(event: IMatrixEvent, mxClient: MatrixClient): Promise<string|Discord.FileOptions> {
+    public async HandleAttachment(
+        event: IMatrixEvent,
+        mxClient: MatrixClient,
+        sendEmbeds: boolean = false,
+    ): Promise<string|Discord.FileOptions|Discord.RichEmbed> {
         if (!this.HasAttachment(event)) {
             return "";
         }
@@ -296,7 +303,7 @@ export class MatrixEventProcessor {
         if (!event.content.info) {
             // Fractal sends images without an info, which is technically allowed
             // but super unhelpful:  https://gitlab.gnome.org/World/fractal/issues/206
-            event.content.info = {size: 0};
+            event.content.info = {mimetype: "", size: 0};
         }
 
         if (!event.content.url) {
@@ -317,6 +324,10 @@ export class MatrixEventProcessor {
                 } as Discord.FileOptions;
             }
         }
+        if (sendEmbeds && event.content.info.mimetype.split("/")[0] === "image") {
+            return new Discord.RichEmbed()
+                .setImage(url);
+        }
         return `[${name}](${url})`;
     }
 
diff --git a/test/test_matrixeventprocessor.ts b/test/test_matrixeventprocessor.ts
index 43eb0c8a6cfc6b98eea212ef6b21193eb416a787..2af10cf8232b809ddb26a5c3336c26c1d8f1fde2 100644
--- a/test/test_matrixeventprocessor.ts
+++ b/test/test_matrixeventprocessor.ts
@@ -603,6 +603,22 @@ describe("MatrixEventProcessor", () => {
             } as IMatrixEvent, mxClient);
             expect(ret).equals("[filename.webm](https://localhost/8000000)");
         });
+        it("Should reply embeds on large info.size images if set", async () => {
+            const LARGE_FILE = 8000000;
+            const processor = createMatrixEventProcessor();
+            const ret = await processor.HandleAttachment({
+                content: {
+                    body: "filename.jpg",
+                    info: {
+                        mimetype: "image/jpeg",
+                        size: LARGE_FILE,
+                    },
+                    msgtype: "m.image",
+                    url: "mxc://localhost/8000000",
+                },
+            } as IMatrixEvent, mxClient, true);
+            expect((ret as Discord.RichEmbed).image!.url).equals("https://localhost/8000000");
+        });
         it("Should handle stickers.", async () => {
             const processor = createMatrixEventProcessor();
             const attachment = (await processor.HandleAttachment({