diff --git a/package.json b/package.json
index 1d441dab479c90f3c8d22e5ab21932498b48ed57..7bd522618090879c60f047c62c0de2b9d86d7a5c 100644
--- a/package.json
+++ b/package.json
@@ -43,7 +43,7 @@
     "escape-string-regexp": "^1.0.5",
     "js-yaml": "^3.10.0",
     "marked": "^0.3.15",
-    "matrix-appservice-bridge": "^1.5.0a",
+    "matrix-appservice-bridge": "^1.7.0",
     "mime": "^1.6.0",
     "moment": "^2.22.2",
     "pg-promise": "^8.5.1",
diff --git a/src/bot.ts b/src/bot.ts
index ec0dc412c35eb6498b67a3761170e33df64c89a8..deed4d7e4a38bd2d9b5a68eb405405d8e67935b9 100644
--- a/src/bot.ts
+++ b/src/bot.ts
@@ -60,7 +60,7 @@ export class DiscordBot {
   public setBridge(bridge: Bridge) {
     this.bridge = bridge;
     this.mxEventProcessor = new MatrixEventProcessor(
-        new MatrixEventProcessorOpts(this.config, bridge),
+        new MatrixEventProcessorOpts(this.config, bridge, this),
     );
   }
 
@@ -235,7 +235,8 @@ export class DiscordBot {
           log.warn(`User ${event.sender} has no member state. That's odd.`);
         }
     }
-    const embed = this.mxEventProcessor.EventToEmbed(event, profile, chan);
+    const embedSet = await this.mxEventProcessor.EventToEmbed(event, profile, chan);
+    const embed = embedSet.messageEmbed;
     const opts: Discord.MessageOptions = {};
     const file = await this.mxEventProcessor.HandleAttachment(event, mxClient);
     if (typeof(file) === "string") {
@@ -260,14 +261,20 @@ export class DiscordBot {
     }
     try {
       if (!botUser) {
+        opts.embed = embedSet.replyEmbed;
         msg = await chan.send(embed.description, opts);
       } else if (hook) {
         msg = await hook.send(embed.description, {
             username: embed.author.name,
             avatarURL: embed.author.icon_url,
-            file: opts.file,
-        });
+            files: opts.file ? [opts.file] : undefined,
+            embeds: embedSet.replyEmbed ? [embedSet.replyEmbed] : undefined,
+        } as any);
       } else {
+        if (embedSet.replyEmbed) {
+            embed.addField("Replying to", embedSet.replyEmbed.author.name);
+            embed.addField("Reply text", embedSet.replyEmbed.description);
+        }
         opts.embed = embed;
         msg = await chan.send("", opts);
       }
@@ -324,6 +331,20 @@ export class DiscordBot {
     return false;
   }
 
+  public GetDiscordUserOrMember(
+      userId: Discord.Snowflake, guildId?: Discord.Snowflake,
+  ): Promise<Discord.User|Discord.GuildMember> {
+        try {
+            if (guildId && this.bot.guilds.has(guildId)) {
+               return this.bot.guilds.get(guildId).fetchMember(userId);
+            }
+            return this.bot.fetchUser(userId);
+        } catch (ex) {
+            log.warn(`Could not fetch user data for ${userId} (guild: ${guildId})`);
+            return undefined;
+        }
+  }
+
   public GetChannelFromRoomId(roomId: string): Promise<Discord.Channel> {
     return this.bridge.getRoomStore().getEntriesByMatrixId(
       roomId,
diff --git a/src/matrixeventprocessor.ts b/src/matrixeventprocessor.ts
index 1ec23a3074f74e723b7400b3179eb859e9dc8e72..93db39566c3f7a91b6f5039cd1c9fa65fb61330a 100644
--- a/src/matrixeventprocessor.ts
+++ b/src/matrixeventprocessor.ts
@@ -6,6 +6,7 @@ import * as escapeStringRegexp from "escape-string-regexp";
 import {Util} from "./util";
 import * as path from "path";
 import * as mime from "mime";
+import {MatrixUser} from "matrix-appservice-bridge";
 
 import { Log } from "./log";
 const log = new Log("MatrixEventProcessor");
@@ -19,18 +20,26 @@ export class MatrixEventProcessorOpts {
     constructor(
         readonly config: DiscordBridgeConfig,
         readonly bridge: any,
+        readonly discord: DiscordBot,
         ) {
 
     }
 }
 
+export interface IMatrixEventProcessorResult {
+    messageEmbed: Discord.RichEmbed;
+    replyEmbed?: Discord.RichEmbed;
+}
+
 export class MatrixEventProcessor {
     private config: DiscordBridgeConfig;
     private bridge: any;
+    private discord: DiscordBot;
 
     constructor (opts: MatrixEventProcessorOpts) {
         this.config = opts.config;
         this.bridge = opts.bridge;
+        this.discord = opts.discord;
     }
 
     public StateEventToMessage(event: any, channel: Discord.TextChannel): string {
@@ -71,7 +80,9 @@ export class MatrixEventProcessor {
         return msg;
     }
 
-    public EventToEmbed(event: any, profile: any|null, channel: Discord.TextChannel): Discord.RichEmbed {
+    public async EventToEmbed(
+        event: any, profile: any|null, channel: Discord.TextChannel,
+    ): Promise<IMatrixEventProcessorResult> {
         let body = this.config.bridge.disableDiscordMentions ? event.content.body :
             this.FindMentionsInPlainBody(
                 event.content.body,
@@ -116,28 +127,14 @@ export class MatrixEventProcessor {
         // Handle discord custom emoji
         body = this.ReplaceDiscordEmoji(body, channel.guild);
 
-        let displayName = event.sender;
-        let avatarUrl = undefined;
-        if (profile) {
-            if (profile.displayname &&
-                profile.displayname.length >= MIN_NAME_LENGTH &&
-                profile.displayname.length <= MAX_NAME_LENGTH) {
-                displayName = profile.displayname;
-            }
-
-            if (profile.avatar_url) {
-                const mxClient = this.bridge.getClientFactory().getClientAs();
-                avatarUrl = mxClient.mxcUrlToHttp(profile.avatar_url);
-            }
-        }
-        return new Discord.RichEmbed({
-            author: {
-                name: displayName.substr(0, MAX_NAME_LENGTH),
-                icon_url: avatarUrl,
-                url: `https://matrix.to/#/${event.sender}`,
-            },
-            description: body,
-        });
+        const messageEmbed = new Discord.RichEmbed();
+        const replyEmbedAndBody = await this.GetEmbedForReply(event);
+        messageEmbed.setDescription(replyEmbedAndBody ? replyEmbedAndBody[1] : body);
+        await this.SetEmbedAuthor(messageEmbed, event.sender, profile);
+        return {
+            messageEmbed,
+            replyEmbed: replyEmbedAndBody ? replyEmbedAndBody[0] : undefined,
+        };
     }
 
     public FindMentionsInPlainBody(body: string, members: Discord.GuildMember[]): string {
@@ -212,6 +209,95 @@ export class MatrixEventProcessor {
         return `[${name}](${url})`;
     }
 
+    public async GetEmbedForReply(event: any): Promise<[Discord.RichEmbed, string]|undefined> {
+        const relatesTo = event.content["m.relates_to"];
+        let eventId = null;
+        if (relatesTo && relatesTo["m.in_reply_to"]) {
+            eventId = relatesTo["m.in_reply_to"].event_id;
+        } else {
+            return;
+        }
+        let reponseText = Util.GetReplyFromReplyBody(event.content.body || "");
+        if (reponseText === "") {
+            reponseText = "Reply with unknown content";
+        }
+
+        const intent = this.bridge.getIntent();
+        const embed = new Discord.RichEmbed();
+        // Try to get the event.
+        try {
+            const sourceEvent = await intent.getEvent(event.room_id, eventId);
+            let replyText = sourceEvent.content.body  || "Reply with unknown content";
+            // Check if this is also a reply.
+            if (sourceEvent.content && sourceEvent.content["m.relates_to"] &&
+                sourceEvent.content["m.relates_to"]["m.in_reply_to"]) {
+                replyText = Util.GetReplyFromReplyBody(sourceEvent.content.body);
+            }
+            embed.setDescription(replyText);
+            await this.SetEmbedAuthor(
+                embed,
+                sourceEvent.sender,
+            );
+        } catch (ex) {
+            log.warn("Failed to handle reply, showing a unknown embed:", ex);
+            // For some reason we failed to get the event, so using fallback.
+            embed.setDescription("Reply with unknown content");
+            embed.setAuthor("Unknown");
+        }
+        return [embed, reponseText];
+    }
+
+    private async SetEmbedAuthor(embed: Discord.RichEmbed, sender: string, profile?: any) {
+        const intent = this.bridge.getIntent();
+        let displayName = sender;
+        let avatarUrl = undefined;
+
+        // Are they a discord user.
+        if (this.bridge.getBot().isRemoteUser(sender)) {
+            const localpart = new MatrixUser(sender.replace("@", "")).localpart;
+            const userOrMember = await this.discord.GetDiscordUserOrMember(localpart.substring("_discord".length));
+            if (userOrMember instanceof Discord.User) {
+                embed.setAuthor(
+                    userOrMember.username,
+                    userOrMember.avatarURL,
+                );
+                return;
+            } else if (userOrMember instanceof Discord.GuildMember) {
+                embed.setAuthor(
+                    userOrMember.displayName,
+                    userOrMember.user.avatarURL,
+                );
+                return;
+            }
+            // Let it fall through.
+        }
+        if (profile === undefined) {
+            try {
+                profile = await intent.getProfileInfo(sender);
+            } catch (ex) {
+                log.warn(`Failed to fetch profile for ${sender}`, ex);
+            }
+        }
+
+        if (profile) {
+            if (profile.displayname &&
+                profile.displayname.length >= MIN_NAME_LENGTH &&
+                profile.displayname.length <= MAX_NAME_LENGTH) {
+                displayName = profile.displayname;
+            }
+
+            if (profile.avatar_url) {
+                const mxClient = this.bridge.getClientFactory().getClientAs();
+                avatarUrl = mxClient.mxcUrlToHttp(profile.avatar_url);
+            }
+        }
+        embed.setAuthor(
+            displayName.substr(0, MAX_NAME_LENGTH),
+            avatarUrl,
+            `https://matrix.to/#/${sender}`,
+        );
+    }
+
     private GetFilenameForMediaEvent(content: any): string {
         if (content.body) {
             if (path.extname(content.body) !== "") {
diff --git a/src/matrixroomhandler.ts b/src/matrixroomhandler.ts
index e627fc9cc463581996b9045b800496a33554b1e5..4fc96a4d476e63bc4cf6cae8e47c497a378fc88d 100644
--- a/src/matrixroomhandler.ts
+++ b/src/matrixroomhandler.ts
@@ -109,7 +109,7 @@ export class MatrixRoomHandler {
     if (event.type === "m.room.member" && event.content.membership === "invite") {
       return this.HandleInvite(event);
     } else if (event.type === "m.room.member" && event.content.membership === "join") {
-        if (this.bridge.getBot()._isRemoteUser(event.state_key)) {
+        if (this.bridge.getBot().isRemoteUser(event.state_key)) {
             return this.discord.UserSyncroniser.OnMemberState(event, USERSYNC_STATE_DELAY_MS);
         } else {
           return this.discord.ProcessMatrixStateEvent(event);
diff --git a/src/util.ts b/src/util.ts
index 61edd636899ea5d785d5717a794313566e7f288e..6346ffe5c140b625fff72acb24f751b95f57c6ae 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -218,7 +218,7 @@ export class Util {
       params[param] = await parameters[param].get(args[i]);
       i++;
     }
-    
+
     const retStr = await action.run(params);
     return retStr;
   }
@@ -237,6 +237,17 @@ export class Util {
     }
     return {command, args};
   }
+
+  public static GetReplyFromReplyBody(body: string) {
+      const lines = body.split("\n");
+      while (lines[0].startsWith("> ") || lines[0].trim().length === 0) {
+          lines.splice(0, 1);
+          if (lines.length === 0) {
+              return "";
+          }
+      }
+      return lines.join("\n").trim();
+  }
 }
 
 interface IUploadResult {
diff --git a/test/test_matrixeventprocessor.ts b/test/test_matrixeventprocessor.ts
index 60b803a6352fe8ad47c7a77299ffcb38feea9c21..e70d16950bdd7e4c710576ee279c97b1b6eade71 100644
--- a/test/test_matrixeventprocessor.ts
+++ b/test/test_matrixeventprocessor.ts
@@ -45,6 +45,11 @@ function createMatrixEventProcessor
                 },
             };
         },
+        getBot: () => {
+            return {
+                isRemoteUser: () => false,
+            };
+        },
         getIntent: () => {
             return {
                 getClient: () => {
@@ -54,6 +59,47 @@ function createMatrixEventProcessor
                         },
                     };
                 },
+                getEvent: async (_, eventId: string) => {
+                    if (eventId === "$goodEvent:localhost") {
+                        return {
+                            sender: "@doggo:localhost",
+                            content: {
+                                body: "Hello!",
+                            },
+                        };
+                    } else if (eventId === "$reply:localhost") {
+                        return {
+                            sender: "@doggo:localhost",
+                            content: {
+                                "body": `> <@doggo:localhost> This is the original body
+
+This is the first reply`,
+                                "m.relates_to": {
+                                    "m.in_reply_to": {
+                                        event_id: "$goodEvent:localhost",
+                                    },
+                                },
+                            },
+                        };
+                    } else if (eventId === "$nontext:localhost") {
+                        return {
+                            sender: "@doggo:localhost",
+                            content: {
+                                something: "not texty",
+                            },
+                        };
+                    }
+                    return null;
+                },
+                getProfileInfo: async (userId: string) => {
+                    if (userId !== "@doggo:localhost") {
+                        return null;
+                    }
+                    return {
+                        displayname: "Doggo!",
+                        avatar_url: "mxc://fakeurl.com",
+                    };
+                },
             };
         },
     };
@@ -61,19 +107,23 @@ function createMatrixEventProcessor
     config.bridge.disableDiscordMentions = disableMentions;
     config.bridge.disableEveryoneMention = disableEveryone;
     config.bridge.disableHereMention = disableHere;
+
+    const Util = Object.assign(require("../src/util").Util, {
+        DownloadFile: (name: string) => {
+            const size = parseInt(name.substring(name.lastIndexOf("/") + 1), undefined);
+            return Buffer.alloc(size);
+        },
+    });
+
     return new (Proxyquire("../src/matrixeventprocessor", {
         "./util": {
-            Util: {
-                DownloadFile: (name: string) => {
-                    const size = parseInt(name.substring(name.lastIndexOf("/") + 1), undefined);
-                    return Buffer.alloc(size);
-                },
-            },
+            Util,
         },
     })).MatrixEventProcessor(
         new MatrixEventProcessorOpts(
             config,
             bridge,
+            null,
     ));
 }
 const mockChannel = new MockChannel();
@@ -203,9 +253,9 @@ describe("MatrixEventProcessor", () => {
         });
     });
     describe("EventToEmbed", () => {
-        it("Should contain a profile.", () => {
+        it("Should contain a profile.", async () => {
             const processor = createMatrixEventProcessor();
-            const evt = processor.EventToEmbed({
+            const embeds = await processor.EventToEmbed({
                 sender: "@test:localhost",
                 content: {
                     body: "testcontent",
@@ -214,53 +264,57 @@ describe("MatrixEventProcessor", () => {
                 displayname: "Test User",
                 avatar_url: "mxc://localhost/avatarurl",
             }, mockChannel as any);
-            Chai.assert.equal(evt.author.name, "Test User");
-            Chai.assert.equal(evt.author.icon_url, "https://localhost/avatarurl");
-            Chai.assert.equal(evt.author.url, "https://matrix.to/#/@test:localhost");
+            const author = embeds.messageEmbed.author;
+            Chai.assert.equal(author.name, "Test User");
+            Chai.assert.equal(author.icon_url, "https://localhost/avatarurl");
+            Chai.assert.equal(author.url, "https://matrix.to/#/@test:localhost");
         });
 
-        it("Should contain the users displayname if it exists.", () => {
+        it("Should contain the users displayname if it exists.", async () => {
             const processor = createMatrixEventProcessor();
-            const evt = processor.EventToEmbed({
+            const embeds = await processor.EventToEmbed({
                 sender: "@test:localhost",
                 content: {
                     body: "testcontent",
                 },
             }, {
                 displayname: "Test User"}, mockChannel as any);
-            Chai.assert.equal(evt.author.name, "Test User");
-            Chai.assert.isUndefined(evt.author.icon_url);
-            Chai.assert.equal(evt.author.url, "https://matrix.to/#/@test:localhost");
+            const author = embeds.messageEmbed.author;
+            Chai.assert.equal(author.name, "Test User");
+            Chai.assert.isUndefined(author.icon_url);
+            Chai.assert.equal(author.url, "https://matrix.to/#/@test:localhost");
         });
 
-        it("Should contain the users userid if the displayname is not set", () => {
+        it("Should contain the users userid if the displayname is not set", async () => {
             const processor = createMatrixEventProcessor();
-            const evt = processor.EventToEmbed({
+            const embeds = await processor.EventToEmbed({
                 sender: "@test:localhost",
                 content: {
                     body: "testcontent",
                 },
             }, null, mockChannel as any);
-            Chai.assert.equal(evt.author.name, "@test:localhost");
-            Chai.assert.isUndefined(evt.author.icon_url);
-            Chai.assert.equal(evt.author.url, "https://matrix.to/#/@test:localhost");
+            const author = embeds.messageEmbed.author;
+            Chai.assert.equal(author.name, "@test:localhost");
+            Chai.assert.isUndefined(author.icon_url);
+            Chai.assert.equal(author.url, "https://matrix.to/#/@test:localhost");
         });
 
-        it("Should use the userid when the displayname is too short", () => {
+        it("Should use the userid when the displayname is too short", async () => {
             const processor = createMatrixEventProcessor();
-            const evt = processor.EventToEmbed({
+            const embeds = await processor.EventToEmbed({
                 sender: "@test:localhost",
                 content: {
                     body: "testcontent",
                 },
             }, {
                 displayname: "t"}, mockChannel as any);
-            Chai.assert.equal(evt.author.name, "@test:localhost");
+            const author = embeds.messageEmbed.author;
+            Chai.assert.equal(author.name, "@test:localhost");
         });
 
-        it("Should use the userid when displayname is too long", () => {
+        it("Should use the userid when displayname is too long", async () => {
             const processor = createMatrixEventProcessor();
-            const evt = processor.EventToEmbed({
+            const embeds = await processor.EventToEmbed({
                 sender: "@test:localhost",
                 content: {
                     body: "testcontent",
@@ -268,78 +322,81 @@ describe("MatrixEventProcessor", () => {
             }, {
                 displayname: "this is a very very long displayname that should be capped",
             }, mockChannel as any);
-            Chai.assert.equal(evt.author.name, "@test:localhost");
+            const author = embeds.messageEmbed.author;
+            Chai.assert.equal(author.name, "@test:localhost");
         });
 
-        it("Should cap the sender name if it is too long", () => {
+        it("Should cap the sender name if it is too long", async () => {
             const processor = createMatrixEventProcessor();
-            const evt = processor.EventToEmbed({
+            const embeds = await processor.EventToEmbed({
                 sender: "@testwithalottosayaboutitselfthatwillgoonandonandonandon:localhost",
                 content: {
                     body: "testcontent",
                 },
             }, null, mockChannel as any);
-            Chai.assert.equal(evt.author.name, "@testwithalottosayaboutitselftha");
+            const author = embeds.messageEmbed.author;
+            Chai.assert.equal(author.name, "@testwithalottosayaboutitselftha");
         });
 
-        it("Should contain the users avatar if it exists.", () => {
+        it("Should contain the users avatar if it exists.", async () => {
             const processor = createMatrixEventProcessor();
-            const evt = processor.EventToEmbed({
+            const embeds = await processor.EventToEmbed({
                 sender: "@test:localhost",
                 content: {
                     body: "testcontent",
                 },
             }, {avatar_url: "mxc://localhost/test"}, mockChannel as any);
-            Chai.assert.equal(evt.author.name, "@test:localhost");
-            Chai.assert.equal(evt.author.icon_url, "https://localhost/test");
-            Chai.assert.equal(evt.author.url, "https://matrix.to/#/@test:localhost");
+            const author = embeds.messageEmbed.author;
+            Chai.assert.equal(author.name, "@test:localhost");
+            Chai.assert.equal(author.icon_url, "https://localhost/test");
+            Chai.assert.equal(author.url, "https://matrix.to/#/@test:localhost");
         });
 
-        it("Should enable mentions if configured.", () => {
+        it("Should enable mentions if configured.", async () => {
             const processor = createMatrixEventProcessor();
-            const evt = processor.EventToEmbed({
+            const embeds = await processor.EventToEmbed({
                 sender: "@test:localhost",
                 content: {
                     body: "@testuser2 Hello!",
                 },
             }, {avatar_url: "test"}, mockChannel as any);
-            Chai.assert.equal(evt.description, "<@!12345> Hello!");
+            Chai.assert.equal(embeds.messageEmbed.description, "<@!12345> Hello!");
         });
 
-        it("Should disable mentions if configured.", () => {
+        it("Should disable mentions if configured.", async () => {
             const processor = createMatrixEventProcessor(true);
-            const evt = processor.EventToEmbed({
+            const embeds = await processor.EventToEmbed({
                 sender: "@test:localhost",
                 content: {
                     body: "@testuser2 Hello!",
                 },
             }, {avatar_url: "test"}, mockChannel as any);
-            Chai.assert.equal(evt.description, "@testuser2 Hello!");
+            Chai.assert.equal(embeds.messageEmbed.description, "@testuser2 Hello!");
         });
 
-        it("Should remove everyone mentions if configured.", () => {
+        it("Should remove everyone mentions if configured.", async () => {
             const processor = createMatrixEventProcessor(false, true);
-            const evt = processor.EventToEmbed({
+            const embeds = await processor.EventToEmbed({
                 sender: "@test:localhost",
                 content: {
                     body: "@everyone Hello!",
                 },
             }, {avatar_url: "test"}, mockChannel as any);
-            Chai.assert.equal(evt.description, "@ everyone Hello!");
+            Chai.assert.equal(embeds.messageEmbed.description, "@ everyone Hello!");
         });
 
-        it("Should remove here mentions if configured.", () => {
+        it("Should remove here mentions if configured.", async () => {
             const processor = createMatrixEventProcessor(false, false, true);
-            const evt = processor.EventToEmbed({
+            const embeds = await processor.EventToEmbed({
                 sender: "@test:localhost",
                 content: {
                     body: "@here Hello!",
                 },
             }, {avatar_url: "test"}, mockChannel as any);
-            Chai.assert.equal(evt.description, "@ here Hello!");
+            Chai.assert.equal(embeds.messageEmbed.description, "@ here Hello!");
         });
 
-        it("Should process custom discord emojis.", () => {
+        it("Should process custom discord emojis.", async () => {
             const processor = createMatrixEventProcessor(false, false, true);
             const mockEmoji = new MockEmoji("123", "supercake");
             const mockCollectionEmojis = new MockCollection<string, MockEmoji>();
@@ -348,16 +405,19 @@ describe("MatrixEventProcessor", () => {
             const mockChannelEmojis = new MockChannel("test", {
                 emojis: mockCollectionEmojis,
             });
-            const evt = processor.EventToEmbed({
+            const embeds = await processor.EventToEmbed({
                 sender: "@test:localhost",
                 content: {
                     body: "I like :supercake:",
                 },
             }, {avatar_url: "test"}, mockChannelEmojis as any);
-            Chai.assert.equal(evt.description, "I like <:supercake:123>");
+            Chai.assert.equal(
+                embeds.messageEmbed.description,
+                "I like <:supercake:123>",
+            );
         });
 
-        it("Should not process invalid custom discord emojis.", () => {
+        it("Should not process invalid custom discord emojis.", async () => {
             const processor = createMatrixEventProcessor(false, false, true);
             const mockEmoji = new MockEmoji("123", "supercake");
             const mockCollectionEmojis = new MockCollection<string, MockEmoji>();
@@ -366,17 +426,20 @@ describe("MatrixEventProcessor", () => {
             const mockChannelEmojis = new MockChannel("test", {
                 emojis: mockCollectionEmojis,
             });
-            const evt = processor.EventToEmbed({
+            const embeds = await processor.EventToEmbed({
                 sender: "@test:localhost",
                 content: {
                     body: "I like :lamecake:",
                 },
             }, {avatar_url: "test"}, mockChannelEmojis as any);
-            Chai.assert.equal(evt.description, "I like :lamecake:");
+            Chai.assert.equal(
+                embeds.messageEmbed.description,
+                "I like :lamecake:",
+            );
         });
-        it("Should replace /me with * displayname, and italicize message", () => {
+        it("Should replace /me with * displayname, and italicize message", async () => {
             const processor = createMatrixEventProcessor();
-            const evt = processor.EventToEmbed({
+            const embeds = await processor.EventToEmbed({
                 sender: "@test:localhost",
                 content: {
                     body: "likes puppies",
@@ -385,11 +448,14 @@ describe("MatrixEventProcessor", () => {
             }, {
                 displayname: "displayname",
             }, mockChannel as any);
-            Chai.assert.equal(evt.description, "*displayname likes puppies*");
+            Chai.assert.equal(
+                embeds.messageEmbed.description,
+                "*displayname likes puppies*",
+            );
         });
-        it("Should handle stickers.", () => {
+        it("Should handle stickers.", async () => {
             const processor = createMatrixEventProcessor();
-            const evt = processor.EventToEmbed({
+            const embeds = await processor.EventToEmbed({
                 sender: "@test:localhost",
                 type: "m.sticker",
                 content: {
@@ -397,7 +463,7 @@ describe("MatrixEventProcessor", () => {
                     url: "mxc://bunny",
                 },
             }, {avatar_url: "test"}, mockChannel as any);
-            Chai.assert.equal(evt.description, "");
+            Chai.assert.equal(embeds.messageEmbed.description, "");
         });
     });
     describe("FindMentionsInPlainBody", () => {
@@ -603,4 +669,125 @@ describe("MatrixEventProcessor", () => {
             });
         });
     });
+    describe("GetEmbedForReply", () => {
+        it("should handle reply-less events", async () => {
+            const processor = createMatrixEventProcessor();
+            const result = await processor.GetEmbedForReply({
+                sender: "@test:localhost",
+                type: "m.room.message",
+                content: {
+                    body: "Test",
+                },
+            });
+            expect(result).to.be.undefined;
+        });
+        it("should handle replies without a fallback", async () => {
+            const processor = createMatrixEventProcessor();
+            const result = await processor.GetEmbedForReply({
+                sender: "@test:localhost",
+                type: "m.room.message",
+                content: {
+                    "body": "Test",
+                    "m.relates_to": {
+                        "m.in_reply_to": {
+                            event_id: "$goodEvent:localhost",
+                        },
+                    },
+                },
+            });
+            expect(result[0].description).to.be.equal("Hello!");
+            expect(result[0].author.name).to.be.equal("Doggo!");
+            expect(result[0].author.icon_url).to.be.equal("https://fakeurl.com");
+            expect(result[0].author.url).to.be.equal("https://matrix.to/#/@doggo:localhost");
+            expect(result[1]).to.be.equal("Test");
+        });
+        it("should handle replies with a missing event", async () => {
+            const processor = createMatrixEventProcessor();
+            const result = await processor.GetEmbedForReply({
+                sender: "@test:localhost",
+                type: "m.room.message",
+                content: {
+                    "body": `> <@doggo:localhost> This is the fake body
+
+This is where the reply goes`,
+                    "m.relates_to": {
+                        "m.in_reply_to": {
+                            event_id: "$event:thing",
+                        },
+                    },
+                },
+            });
+            expect(result[0].description).to.be.equal("Reply with unknown content");
+            expect(result[0].author.name).to.be.equal("Unknown");
+            expect(result[0].author.icon_url).to.be.undefined;
+            expect(result[0].author.url).to.be.undefined;
+            expect(result[1]).to.be.equal("This is where the reply goes");
+        });
+        it("should handle replies with a valid reply event", async () => {
+            const processor = createMatrixEventProcessor();
+            const result = await processor.GetEmbedForReply({
+                sender: "@test:localhost",
+                type: "m.room.message",
+                content: {
+                    "body": `> <@doggo:localhost> This is the original body
+
+This is where the reply goes`,
+                    "m.relates_to": {
+                        "m.in_reply_to": {
+                            event_id: "$goodEvent:localhost",
+                        },
+                    },
+                },
+            });
+            expect(result[0].description).to.be.equal("Hello!");
+            expect(result[0].author.name).to.be.equal("Doggo!");
+            expect(result[0].author.icon_url).to.be.equal("https://fakeurl.com");
+            expect(result[0].author.url).to.be.equal("https://matrix.to/#/@doggo:localhost");
+            expect(result[1]).to.be.equal("This is where the reply goes");
+        });
+        it("should handle replies on top of replies", async () => {
+            const processor = createMatrixEventProcessor();
+            const result = await processor.GetEmbedForReply({
+                sender: "@test:localhost",
+                type: "m.room.message",
+                content: {
+                    "body": `> <@doggo:localhost> This is the first reply
+
+This is the second reply`,
+                    "m.relates_to": {
+                        "m.in_reply_to": {
+                            event_id: "$reply:localhost",
+                        },
+                    },
+                },
+            });
+            expect(result[0].description).to.be.equal("This is the first reply");
+            expect(result[0].author.name).to.be.equal("Doggo!");
+            expect(result[0].author.icon_url).to.be.equal("https://fakeurl.com");
+            expect(result[0].author.url).to.be.equal("https://matrix.to/#/@doggo:localhost");
+            expect(result[1]).to.be.equal("This is the second reply");
+        });
+        it("should handle replies with non text events", async () => {
+            const processor = createMatrixEventProcessor();
+            const result = await processor.GetEmbedForReply({
+                sender: "@test:localhost",
+                type: "m.room.message",
+                content: {
+                    "body": `> <@doggo:localhost> sent an image.
+
+This is the reply`,
+                    "m.relates_to": {
+                        "m.in_reply_to": {
+                            event_id: "$nontext:localhost",
+                        },
+                    },
+                },
+            });
+            expect(result[0].description).to.be.equal("Reply with unknown content");
+            expect(result[0].author.name).to.be.equal("Doggo!");
+            expect(result[0].author.icon_url).to.be.equal("https://fakeurl.com");
+            expect(result[0].author.url).to.be.equal("https://matrix.to/#/@doggo:localhost");
+            expect(result[1]).to.be.equal("This is the reply");
+        });
+    });
 });
diff --git a/test/test_matrixroomhandler.ts b/test/test_matrixroomhandler.ts
index 0bfefe5e45be2aab7401b65d23c24f451da4f639..aa2b5f641b5c483040e7600d8a9fdd9537dae00c 100644
--- a/test/test_matrixroomhandler.ts
+++ b/test/test_matrixroomhandler.ts
@@ -66,7 +66,7 @@ function createRH(opts: any = {}) {
         },
         getBot: () => {
             return {
-                _isRemoteUser: (id) => {
+                isRemoteUser: (id) => {
                     return id !== undefined && id.startsWith("@_discord_");
                 },
             };
diff --git a/test/test_util.ts b/test/test_util.ts
index ccc810b872048f81b49b5092d0572b2632a38631..dc48346bf48a8c85bbeaf673c49eb804f24590ec 100644
--- a/test/test_util.ts
+++ b/test/test_util.ts
@@ -116,4 +116,28 @@ describe("Util", () => {
             return expect(Util.GetMxidFromName(intent, "badboy", ["abc"])).to.eventually.be.rejected;
         });
     });
+    describe("GetReplyFromReplyBody", () => {
+        it("Should get a reply from the body", () => {
+            const reply = Util.GetReplyFromReplyBody(`> <@alice:example.org> This is the original body
+
+This is where the reply goes`);
+            return expect(reply).to.equal("This is where the reply goes");
+        });
+        it("Should get a multi-line reply from the body", () => {
+            const reply = Util.GetReplyFromReplyBody(`> <@alice:example.org> This is the original body
+
+This is where the reply goes and
+there are even more lines here.`);
+            return expect(reply).to.equal("This is where the reply goes and\nthere are even more lines here.");
+        });
+        it("Should get empty string from an empty reply", () => {
+            const reply = Util.GetReplyFromReplyBody(`> <@alice:example.org> This is the original body
+`);
+            return expect(reply).to.equal("");
+        });
+        it("Should return body if no reply found", () => {
+            const reply = Util.GetReplyFromReplyBody("Test\nwith\nhalfy");
+            return expect(reply).to.equal("Test\nwith\nhalfy");
+        });
+    });
 });