diff --git a/src/bot.ts b/src/bot.ts
index ec0dc412c35eb6498b67a3761170e33df64c89a8..afa7b438944a2f36486547f090e80bab2f4df408 100644
--- a/src/bot.ts
+++ b/src/bot.ts
@@ -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,
-        });
+            embed: embedSet.replyEmbed,
+        } as Discord.WebhookMessageOptions);
       } 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);
       }
diff --git a/src/matrixeventprocessor.ts b/src/matrixeventprocessor.ts
index 1ec23a3074f74e723b7400b3179eb859e9dc8e72..f9ed11839c97be24cc475ee6bf6328a171cdd467 100644
--- a/src/matrixeventprocessor.ts
+++ b/src/matrixeventprocessor.ts
@@ -14,6 +14,7 @@ const MaxFileSize = 8000000;
 const MIN_NAME_LENGTH = 2;
 const MAX_NAME_LENGTH = 32;
 const DISCORD_EMOJI_REGEX = /:(\w+):/g;
+const REPLY_REGEX = /> <(@.*:.*)> (.*)\n\n(.*)/;
 
 export class MatrixEventProcessorOpts {
     constructor(
@@ -24,6 +25,11 @@ export class MatrixEventProcessorOpts {
     }
 }
 
+export interface MatrixEventProcessorResult {
+    messageEmbed: Discord.RichEmbed;
+    replyEmbed?: Discord.RichEmbed;
+}
+
 export class MatrixEventProcessor {
     private config: DiscordBridgeConfig;
     private bridge: any;
@@ -71,7 +77,7 @@ 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<MatrixEventProcessorResult> {
         let body = this.config.bridge.disableDiscordMentions ? event.content.body :
             this.FindMentionsInPlainBody(
                 event.content.body,
@@ -116,28 +122,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);
+        this.SetEmbedAuthor(messageEmbed, event.sender, profile);
+        return {
+            messageEmbed,
+            replyEmbed: replyEmbedAndBody ? replyEmbedAndBody[0] : undefined,
+        };
     }
 
     public FindMentionsInPlainBody(body: string, members: Discord.GuildMember[]): string {
@@ -212,6 +204,74 @@ 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;
+        }
+        const matches = REPLY_REGEX.exec(event.content.body);
+        if (!matches || matches.length !== 4) {
+            return;
+        }
+        const intent = this.bridge.getIntent();
+        const embed = new Discord.RichEmbed();
+        // Try to get the event.
+        try {
+            const sourceEvent = await intent.getEvent(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"]) {
+                const sourceMatch = REPLY_REGEX.exec(sourceEvent.content.body);
+                if (sourceMatch && sourceMatch.length === 4) {
+                    replyText = sourceMatch[3];
+                }
+            }
+            embed.setDescription(replyText);
+            this.SetEmbedAuthor(
+                embed,
+                sourceEvent.sender,
+                await intent.getProfileInfo(sourceEvent.sender)
+            );
+        } catch (ex) {
+            // For some reason we failed to get the event, so using fallback.
+            embed.setDescription(matches[2]);
+            this.SetEmbedAuthor(
+                embed,
+                matches[1],
+                await intent.getProfileInfo(matches[1])
+            );
+        }
+        return [embed, matches[3]];
+    }
+
+    private SetEmbedAuthor(embed: Discord.RichEmbed, sender: string, profile: any) {
+        const intent = this.bridge.getIntent();
+        let displayName = 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);
+            }
+        }
+        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/test/test_matrixeventprocessor.ts b/test/test_matrixeventprocessor.ts
index 60b803a6352fe8ad47c7a77299ffcb38feea9c21..037d0b994c3e002e39c1ec79f2243fe9a28f8ad9 100644
--- a/test/test_matrixeventprocessor.ts
+++ b/test/test_matrixeventprocessor.ts
@@ -54,6 +54,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",
+                    };
+                },
             };
         },
     };
@@ -203,9 +244,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 +255,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 +313,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.", () => {
-            const processor = createMatrixEventProcessor();
-            const evt = processor.EventToEmbed({
+        it("Should enable mentions if configured.", async () => {
+            const processor = await createMatrixEventProcessor();
+            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 +396,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 +417,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 +439,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 +454,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 +660,121 @@ 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 with a wrongly formatted body", 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: "!event:thing",
+                        },
+                    },
+                },
+            });
+            expect(result).to.be.undefined;
+        });
+        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("This is the fake body");
+            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 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");
+        });
+    });
 });