diff --git a/src/bot.ts b/src/bot.ts
index c6053d6cb45c86bfce83859ab31ef50801d5836f..44688901193671603f4b2513eaef93bd6b22fb3c 100644
--- a/src/bot.ts
+++ b/src/bot.ts
@@ -30,7 +30,7 @@ import { MatrixRoomHandler } from "./matrixroomhandler";
 import { Log } from "./log";
 import * as Discord from "discord.js";
 import * as mime from "mime";
-import { IMatrixEvent, IMatrixMediaInfo } from "./matrixtypes";
+import { IMatrixEvent, IMatrixMediaInfo, IMatrixMessage } from "./matrixtypes";
 import { Appservice, Intent } from "matrix-bot-sdk";
 import { DiscordCommandHandler } from "./discordcommandhandler";
 import { MetricPeg } from "./metrics";
@@ -388,6 +388,75 @@ export class DiscordBot {
         this.channelLock.release(channel.id);
     }
 
+    /**
+     * Edits an event on Discord.
+     * @throws {Unstable.ForeignNetworkError}
+     */
+    public async edit(
+        embedSet: IMatrixEventProcessorResult,
+        opts: Discord.MessageOptions,
+        roomLookup: ChannelLookupResult,
+        event: IMatrixEvent,
+        editEventId: string,
+    ): Promise<void> {
+        const chan = roomLookup.channel;
+        const botUser = roomLookup.botUser;
+        const embed = embedSet.messageEmbed;
+        const oldMsg = await chan.fetchMessage(editEventId);
+        if (!oldMsg) {
+            // old message not found, just sending this normally
+            await this.send(embedSet, opts, roomLookup, event);
+            return;
+        }
+        if (!botUser) {
+            try {
+                if (!roomLookup.canSendEmbeds) {
+                    await oldMsg.edit(this.prepareEmbedSetUserAccount(embedSet), opts);
+                } else {
+                    opts.embed = this.prepareEmbedSetBotAccount(embedSet);
+                    await oldMsg.edit(embed.description, opts);
+                }
+                return;
+            } catch (err) {
+                log.warning("Failed to edit discord message, falling back to delete and resend...", err);
+            }
+        }
+        try {
+            if (editEventId === this.lastEventIds[chan.id]) {
+                log.info("Immediate edit, deleting and re-sending");
+                this.channelLock.set(chan.id);
+                // we need to delete the event off of the store
+                // else the delete bridges over back to matrix
+                const dbEvent = await this.store.Get(DbEvent, { discord_id: editEventId });
+                log.verbose("Event to delete", dbEvent);
+                if (dbEvent && dbEvent.Next()) {
+                    await this.store.Delete(dbEvent);
+                }
+                await oldMsg.delete();
+                this.channelLock.release(chan.id);
+                const msg = await this.send(embedSet, opts, roomLookup, event, true);
+                // we re-insert the old matrix event with the new discord id
+                // to allow consecutive edits, as matrix edits are typically
+                // done on the original event
+                const dummyEvent = {
+                    event_id: event.content!["m.relates_to"].event_id,
+                    room_id: event.room_id,
+                } as IMatrixEvent;
+                this.StoreMessagesSent(msg, chan, dummyEvent).catch(() => {
+                    log.warn("Failed to store edit sent message for ", event.event_id);
+                });
+                return;
+            }
+            const link = `https://discordapp.com/channels/${chan.guild.id}/${chan.id}/${editEventId}`;
+            embedSet.messageEmbed.description = `[Edit](${link}): ${embedSet.messageEmbed.description}`;
+            await this.send(embedSet, opts, roomLookup, event);
+        } catch (err) {
+            // throw wrapError(err, Unstable.ForeignNetworkError, "Couldn't edit message");
+            log.warn(`Failed to edit message ${event.event_id}`);
+            log.verbose(err);
+        }
+    }
+
     /**
      * Sends an event to Discord.
      * @throws {Unstable.ForeignNetworkError}
@@ -397,7 +466,8 @@ export class DiscordBot {
         opts: Discord.MessageOptions,
         roomLookup: ChannelLookupResult,
         event: IMatrixEvent,
-    ): Promise<void> {
+        awaitStore: boolean = false,
+    ): Promise<Discord.Message | null | (Discord.Message | null)[]> {
         const chan = roomLookup.channel;
         const botUser = roomLookup.botUser;
         const embed = embedSet.messageEmbed;
@@ -424,43 +494,13 @@ export class DiscordBot {
             this.channelLock.set(chan.id);
             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);
+                msg = await chan.send(this.prepareEmbedSetUserAccount(embedSet), 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;
-                }
+                opts.embed = this.prepareEmbedSetBotAccount(embedSet);
                 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);
-                }
+                const embeds = this.prepareEmbedSetWebhook(embedSet);
                 msg = await hook.send(embed.description, {
                     avatarURL: embed!.author!.icon_url,
                     embeds,
@@ -468,27 +508,24 @@ export class DiscordBot {
                     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);
-                }
-                opts.embed = embed;
+                opts.embed = this.prepareEmbedSetBot(embedSet);
                 msg = await chan.send("", opts);
             }
             // Don't block on this.
-            this.StoreMessagesSent(msg, chan, event).then(() => {
+            const storePromise = this.StoreMessagesSent(msg, chan, event).then(() => {
                 this.channelLock.release(chan.id);
             }).catch(() => {
                 log.warn("Failed to store sent message for ", event.event_id);
             });
+            if (awaitStore) {
+                await storePromise;
+            }
         } catch (err) {
             // throw wrapError(err, Unstable.ForeignNetworkError, "Couldn't send message");
             log.warn(`Failed to send message ${event.event_id}`);
             log.verbose(err);
         }
+        return msg;
     }
 
     public async ProcessMatrixRedact(event: IMatrixEvent) {
@@ -720,6 +757,63 @@ export class DiscordBot {
         return dbEmoji;
     }
 
+    private prepareEmbedSetUserAccount(embedSet: IMatrixEventProcessorResult): string {
+        const embed = embedSet.messageEmbed;
+        let addText = "";
+        if (embedSet.replyEmbed) {
+            for (const line of embedSet.replyEmbed.description!.split("\n")) {
+                addText += "\n> " + line;
+            }
+        }
+        return embed.description += addText;
+    }
+
+    private prepareEmbedSetBotAccount(embedSet: IMatrixEventProcessorResult): Discord.RichEmbed | undefined {
+        if (!embedSet.imageEmbed && !embedSet.replyEmbed) {
+            return undefined;
+        }
+        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);
+            }
+        }
+        return sendEmbed;
+    }
+
+    private prepareEmbedSetWebhook(embedSet: IMatrixEventProcessorResult): Discord.RichEmbed[] {
+        const embeds: Discord.RichEmbed[] = [];
+        if (embedSet.imageEmbed) {
+            embeds.push(embedSet.imageEmbed);
+        }
+        if (embedSet.replyEmbed) {
+            embeds.push(embedSet.replyEmbed);
+        }
+        return embeds;
+    }
+
+    private prepareEmbedSetBot(embedSet: IMatrixEventProcessorResult): Discord.RichEmbed {
+        const embed = embedSet.messageEmbed;
+        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);
+        }
+        return embed;
+    }
+
     private async SendMatrixMessage(matrixMsg: IDiscordMessageParserResult, chan: Discord.Channel,
                                     guild: Discord.Guild, author: Discord.User,
                                     msgID: string): Promise<boolean> {
@@ -759,7 +853,7 @@ export class DiscordBot {
         }
     }
 
-    private async OnMessage(msg: Discord.Message) {
+    private async OnMessage(msg: Discord.Message, editEventId: string = "") {
         const indexOfMsg = this.sentMessages.indexOf(msg.id);
         if (indexOfMsg !== -1) {
             log.verbose("Got repeated message, ignoring.");
@@ -810,49 +904,55 @@ export class DiscordBot {
         try {
             const intent = this.GetIntentFromDiscordMember(msg.author, msg.webhookID);
             // Check Attachements
-            await Util.AsyncForEach(msg.attachments.array(), async (attachment) => {
-                const content = await Util.DownloadFile(attachment.url);
-                const fileMime = content.mimeType || mime.getType(attachment.filename) || "application/octet-stream";
-                const mxcUrl = await intent.underlyingClient.uploadContent(
-                    content.buffer,
-                    fileMime,
-                    attachment.filename,
-                );
-                const type = fileMime.split("/")[0];
-                let msgtype = {
-                    audio: "m.audio",
-                    image: "m.image",
-                    video: "m.video",
-                }[type];
-                if (!msgtype) {
-                    msgtype = "m.file";
-                }
-                const info = {
-                    mimetype: fileMime,
-                    size: attachment.filesize,
-                } as IMatrixMediaInfo;
-                if (msgtype === "m.image" || msgtype === "m.video") {
-                    info.w = attachment.width;
-                    info.h = attachment.height;
-                }
-                await Util.AsyncForEach(rooms, async (room) => {
-                    const eventId = await intent.sendEvent(room, {
-                        body: attachment.filename,
-                        external_url: attachment.url,
-                        info,
-                        msgtype,
-                        url: mxcUrl,
+            if (!editEventId) {
+                // on discord you can't edit in images, you can only edit text
+                // so it is safe to only check image upload stuff if we don't have
+                // an edit
+                await Util.AsyncForEach(msg.attachments.array(), async (attachment) => {
+                    const content = await Util.DownloadFile(attachment.url);
+                    const fileMime = content.mimeType || mime.getType(attachment.filename)
+                        || "application/octet-stream";
+                    const mxcUrl = await intent.underlyingClient.uploadContent(
+                        content.buffer,
+                        fileMime,
+                        attachment.filename,
+                    );
+                    const type = fileMime.split("/")[0];
+                    let msgtype = {
+                        audio: "m.audio",
+                        image: "m.image",
+                        video: "m.video",
+                    }[type];
+                    if (!msgtype) {
+                        msgtype = "m.file";
+                    }
+                    const info = {
+                        mimetype: fileMime,
+                        size: attachment.filesize,
+                    } as IMatrixMediaInfo;
+                    if (msgtype === "m.image" || msgtype === "m.video") {
+                        info.w = attachment.width;
+                        info.h = attachment.height;
+                    }
+                    await Util.AsyncForEach(rooms, async (room) => {
+                        const eventId = await intent.sendEvent(room, {
+                            body: attachment.filename,
+                            external_url: attachment.url,
+                            info,
+                            msgtype,
+                            url: mxcUrl,
+                        });
+                        this.lastEventIds[room] = eventId;
+                        const evt = new DbEvent();
+                        evt.MatrixId = `${eventId};${room}`;
+                        evt.DiscordId = msg.id;
+                        evt.ChannelId = msg.channel.id;
+                        evt.GuildId = msg.guild.id;
+                        await this.store.Insert(evt);
                     });
-                    this.lastEventIds[room] = eventId;
-                    const evt = new DbEvent();
-                    evt.MatrixId = `${eventId};${room}`;
-                    evt.DiscordId = msg.id;
-                    evt.ChannelId = msg.channel.id;
-                    evt.GuildId = msg.guild.id;
-                    await this.store.Insert(evt);
                 });
-            });
-            if (msg.content === null) {
+            }
+            if (!msg.content && msg.embeds.length === 0) {
                 return;
             }
             const result = await this.discordMsgProcessor.FormatMessage(msg);
@@ -860,12 +960,27 @@ export class DiscordBot {
                 return;
             }
             await Util.AsyncForEach(rooms, async (room) => {
-                const trySend = async () => intent.sendEvent(room, {
+                const sendContent: IMatrixMessage = {
                     body: result.body,
                     format: "org.matrix.custom.html",
                     formatted_body: result.formattedBody,
                     msgtype: result.msgtype,
-                });
+                };
+                if (editEventId) {
+                    sendContent.body = `* ${result.body}`;
+                    sendContent.formatted_body = `* ${result.formattedBody}`;
+                    sendContent["m.new_content"] = {
+                        body: result.body,
+                        format: "org.matrix.custom.html",
+                        formatted_body: result.formattedBody,
+                        msgtype: result.msgtype,
+                    };
+                    sendContent["m.relates_to"] = {
+                        event_id: editEventId,
+                        rel_type: "m.replace",
+                    };
+                }
+                const trySend = async () =>  intent.sendEvent(room, sendContent);
                 const afterSend = async (eventId) => {
                     this.lastEventIds[room] = eventId;
                     const evt = new DbEvent();
@@ -906,28 +1021,16 @@ export class DiscordBot {
             return;
         }
         log.info(`Got edit event for ${newMsg.id}`);
-        let link = "";
         const storeEvent = await this.store.Get(DbEvent, {discord_id: oldMsg.id});
         if (storeEvent && storeEvent.Result) {
             while (storeEvent.Next()) {
                 const matrixIds = storeEvent.MatrixId.split(";");
-                if (matrixIds[0] === this.lastEventIds[matrixIds[1]]) {
-                    log.info("Immediate edit, deleting and re-sending");
-                    await this.DeleteDiscordMessage(oldMsg);
-                    await this.OnMessage(newMsg);
-                    return;
-                }
-                link = `https://matrix.to/#/${matrixIds[1]}/${matrixIds[0]}`;
+                await this.OnMessage(newMsg, matrixIds[0]);
+                return;
             }
         }
-
-        // Create a new edit message using the old and new message contents
-        const editedMsg = await this.discordMsgProcessor.FormatEdit(oldMsg, newMsg, link);
-
-        // Send the message to all bridged matrix rooms
-        if (!await this.SendMatrixMessage(editedMsg, newMsg.channel, newMsg.guild, newMsg.author, newMsg.id)) {
-            log.error("Unable to announce message edit for msg id:", newMsg.id);
-        }
+        newMsg.content = `Edit: ${newMsg.content}`;
+        await this.OnMessage(newMsg);
     }
 
     private async DeleteDiscordMessage(msg: Discord.Message) {
@@ -969,7 +1072,7 @@ export class DiscordBot {
             }
             log.verbose("Sent ", m.id);
             this.sentMessages.push(m.id);
-            this.lastEventIds[event.room_id] = event.event_id;
+            this.lastEventIds[chan.id] = m.id;
             try {
                 const evt = new DbEvent();
                 evt.MatrixId = `${event.event_id};${event.room_id}`;
diff --git a/src/matrixeventprocessor.ts b/src/matrixeventprocessor.ts
index ae6eed4b0cab6bc68c2fb152fc7cbd41dbacf1db..388fe1521f6a78fce94bfc3ed43d2b1b40e8c8f7 100644
--- a/src/matrixeventprocessor.ts
+++ b/src/matrixeventprocessor.ts
@@ -23,6 +23,8 @@ import * as mime from "mime";
 import { IMatrixEvent, IMatrixEventContent, IMatrixMessage } from "./matrixtypes";
 import { MatrixMessageProcessor, IMatrixMessageProcessorParams } from "./matrixmessageprocessor";
 import { MatrixCommandHandler } from "./matrixcommandhandler";
+import { DbEvent } from "./db/dbdataevent";
+
 import { Log } from "./log";
 import { IRoomStoreEntry, RemoteStoreRoom } from "./db/roomstore";
 import { Appservice, MatrixClient } from "matrix-bot-sdk";
@@ -69,6 +71,7 @@ export class MatrixEventProcessor {
     constructor(opts: MatrixEventProcessorOpts, cm?: MatrixCommandHandler) {
         this.config = opts.config;
         this.bridge = opts.bridge;
+        this.store = opts.store;
         this.discord = opts.discord;
         this.store = opts.store;
         this.matrixMsgProcessor = new MatrixMessageProcessor(this.discord, this.config);
@@ -186,6 +189,15 @@ export class MatrixEventProcessor {
         const roomLookup = await this.discord.LookupRoom(guildId, channelId, event.sender);
         const chan = roomLookup.channel;
 
+        let editEventId = "";
+        if (event.content && event.content["m.relates_to"] && event.content["m.relates_to"].rel_type === "m.replace") {
+            const editMatrixId = `${event.content["m.relates_to"].event_id};${event.room_id}`;
+            const storeEvent = await this.store.Get(DbEvent, {matrix_id: editMatrixId});
+            if (storeEvent && storeEvent.Result && storeEvent.Next()) {
+                editEventId = storeEvent.DiscordId;
+            }
+        }
+
         const embedSet = await this.EventToEmbed(event, chan);
         const opts: Discord.MessageOptions = {};
         const file = await this.HandleAttachment(event, mxClient, roomLookup.canSendEmbeds);
@@ -197,9 +209,13 @@ export class MatrixEventProcessor {
             embedSet.imageEmbed = file as Discord.RichEmbed;
         }
 
-        // Throws an `Unstable.ForeignNetworkError` when sending the message fails.
-        await this.discord.send(embedSet, opts, roomLookup, event);
-
+    // Throws an `Unstable.ForeignNetworkError` when sending the message fails.
+        if (editEventId) {
+            await this.discord.edit(embedSet, opts, roomLookup, event, editEventId);
+        } else {
+            await this.discord.send(embedSet, opts, roomLookup, event);
+        }
+        // Don't await this.
         this.sendReadReceipt(event).catch((ex) => {
             log.verbose("Failed to send read reciept for ", event.event_id, ex);
         });
@@ -283,7 +299,8 @@ export class MatrixEventProcessor {
 
         let body: string = "";
         if (event.type !== "m.sticker") {
-            body = await this.matrixMsgProcessor.FormatMessage(event.content as IMatrixMessage, channel.guild, params);
+            const content = event.content!["m.new_content"] ? event.content!["m.new_content"] : event.content;
+            body = await this.matrixMsgProcessor.FormatMessage(content as IMatrixMessage, channel.guild, params);
         }
 
         const messageEmbed = new Discord.RichEmbed();
diff --git a/src/matrixtypes.ts b/src/matrixtypes.ts
index f08ae1301c571fdbc866e7aafff94eed21e8229f..439d73439f7f0de58dc3452f41edec098da3d171 100644
--- a/src/matrixtypes.ts
+++ b/src/matrixtypes.ts
@@ -52,6 +52,8 @@ export interface IMatrixMessage {
     msgtype: string;
     formatted_body?: string;
     format?: string;
+    "m.new_content"?: any; // tslint:disable-line no-any
+    "m.relates_to"?: any; // tslint:disable-line no-any
 }
 
 export interface IMatrixMediaInfo {
diff --git a/test/mocks/appservicemock.ts b/test/mocks/appservicemock.ts
index b832db55365c5c8b23e3ffa7ba3ae1cd38c14984..5aaf9ca2e873416efaaea1aea49e688d36a91dde 100644
--- a/test/mocks/appservicemock.ts
+++ b/test/mocks/appservicemock.ts
@@ -73,6 +73,10 @@ export class AppserviceMock extends AppserviceMockBase {
     constructor(private opts: IAppserviceMockOpts = {}) {
         super();
         opts.roommembers = opts.roommembers || [];
+        this.cleanup();
+    }
+
+    public cleanup() {
         this.intents = {};
         this.botIntent = new IntentMock(this.opts, "BOT");
         this.botClient = this.botIntent.underlyingClient;
@@ -163,8 +167,8 @@ class IntentMock extends AppserviceMockBase {
         this.funcCalled("sendText", roomId, body);
     }
 
-    public sendEvent(roomId: string, body: string) {
-        this.funcCalled("sendEvent", roomId, body);
+    public sendEvent(roomId: string, content: any) {
+        this.funcCalled("sendEvent", roomId, content);
     }
 
     public async ensureRegistered(): Promise<void> {
diff --git a/test/test_discordbot.ts b/test/test_discordbot.ts
index dd4a1a1250be7134911ecc3ba260efa7c10d41f6..f8e6e181660bf1e61a2364546582aecefb71b005 100644
--- a/test/test_discordbot.ts
+++ b/test/test_discordbot.ts
@@ -109,6 +109,7 @@ describe("DiscordBot", () => {
         let HANDLE_COMMAND = false;
         function getDiscordBot() {
             HANDLE_COMMAND = false;
+            mockBridge.cleanup();
             const discord = new modDiscordBot.DiscordBot(
                 config,
                 mockBridge,
@@ -160,6 +161,25 @@ describe("DiscordBot", () => {
             await discordBot.OnMessage(msg as any);
             mockBridge.getIntent(author.id).wasCalled("sendEvent");
         });
+        it("sends edit messages", async () => {
+            discordBot = getDiscordBot();
+            msg.author = author;
+            msg.content = "Foxies are super amazing!";
+            await discordBot.OnMessage(msg, "editevent");
+            mockBridge.getIntent(author.id).wasCalled("sendEvent", true,  "!asdf:localhost", {
+                "body": "* Foxies are super amazing!",
+                "format": "org.matrix.custom.html",
+                "formatted_body": "* Foxies are super amazing!",
+                "m.new_content": {
+                    body: "Foxies are super amazing!",
+                    format: "org.matrix.custom.html",
+                    formatted_body: "Foxies are super amazing!",
+                    msgtype: "m.text",
+                },
+                "m.relates_to": { event_id: "editevent", rel_type: "m.replace" },
+                "msgtype": "m.text",
+            });
+        });
         it("uploads images", async () => {
             discordBot = getDiscordBot();
             msg.author = author;
@@ -288,7 +308,7 @@ describe("DiscordBot", () => {
             await discordBot.OnMessageUpdate(oldMsg, newMsg);
             expect(checkMsgSent).to.be.false;
         });
-        it("should send a matrix message on an edited discord message", async () => {
+        it("should send a matrix edit on an edited discord message", async () => {
             discordBot = new modDiscordBot.DiscordBot(
                 config,
                 mockBridge,
@@ -308,14 +328,26 @@ describe("DiscordBot", () => {
             oldMsg.content = "a";
             newMsg.content = "b";
 
-            // Mock the SendMatrixMessage method to check if it is called
-            let checkMsgSent = false;
-            discordBot.SendMatrixMessage = (...args) => checkMsgSent = true;
+            let storeMockResults = 1;
+            discordBot.store = {
+                Get: (a, b) => {
+                    return {
+                        MatrixId: "editedid",
+                        Next: () => storeMockResults--,
+                        Result: true,
+                    };
+                },
+            };
+
+            let checkEditEventSent = "";
+            discordBot.OnMessage = (str, event) => {
+                checkEditEventSent = event;
+            };
 
             await discordBot.OnMessageUpdate(oldMsg, newMsg);
-            expect(checkMsgSent).to.be.true;
+            expect(checkEditEventSent).to.equal("editedid");
         });
-        it("should delete and re-send if it is the newest message", async () => {
+        it("should send a new message if no store event found", async () => {
             discordBot = new modDiscordBot.DiscordBot(
                 config,
                 mockBridge,
@@ -340,14 +372,24 @@ describe("DiscordBot", () => {
             oldMsg.content = "a";
             newMsg.content = "b";
 
-            let deletedMessage = false;
-            discordBot.DeleteDiscordMessage = async (_) => { deletedMessage = true; };
-            let sentMessage = false;
-            discordBot.OnMessage = async (_) => { sentMessage = true; };
+            let storeMockResults = 0;
+            discordBot.store = {
+                Get: (a, b) => {
+                    return {
+                        MatrixId: "editedid",
+                        Next: () => storeMockResults--,
+                        Result: true,
+                    };
+                },
+            };
+
+            let checkEditEventSent = "wrong";
+            discordBot.OnMessage = (str, event) => {
+                checkEditEventSent = event;
+            };
 
             await discordBot.OnMessageUpdate(oldMsg, newMsg);
-            expect(deletedMessage).to.be.true;
-            expect(sentMessage).to.be.true;
+            expect(checkEditEventSent).to.be.undefined;
         });
     });
     describe("event:message", () => {
diff --git a/test/test_matrixeventprocessor.ts b/test/test_matrixeventprocessor.ts
index 3b3734bca21629e092569f3e4c9b4b82f8b8aaf3..b00248099467a3cb3b430ec02566cb5b5d9ef569 100644
--- a/test/test_matrixeventprocessor.ts
+++ b/test/test_matrixeventprocessor.ts
@@ -151,11 +151,15 @@ const profileFetcher = async (userId) => {
 let STATE_EVENT_MSG = "";
 let MESSAGE_PROCCESS = "";
 let KICKBAN_HANDLED = false;
+let MESSAGE_SENT = false;
+let MESSAGE_EDITED = false;
 
-function createMatrixEventProcessor() {
+function createMatrixEventProcessor(storeMockResults = 0) {
     STATE_EVENT_MSG = "";
     MESSAGE_PROCCESS = "";
     KICKBAN_HANDLED = false;
+    MESSAGE_SENT = false;
+    MESSAGE_EDITED = false;
     const bridge = new AppserviceMock({
         botUserId: "@botuser:localhost",
         eventFetcher,
@@ -170,6 +174,18 @@ function createMatrixEventProcessor() {
     };
     const config = new DiscordBridgeConfig();
 
+    const store = {
+        Get: (a, b) => {
+            return {
+                DiscordId: "123456",
+                MatrixId: "editedevent",
+                Next: () => storeMockResults--,
+                Result: true,
+            };
+        },
+        removeEntriesByMatrixRoomId: () => Promise.resolve(),
+    };
+
     const Util = Object.assign(require("../src/util").Util, {
         DownloadFile: (name: string) => {
             const size = parseInt(name.substring(name.lastIndexOf("/") + 1), undefined);
@@ -187,10 +203,22 @@ function createMatrixEventProcessor() {
         HandleMatrixKickBan: () => {
             KICKBAN_HANDLED = true;
         },
+        LookupRoom: async (guildId, chanId) => {
+            return {
+                botUser: true,
+                canSendEmbeds: true,
+            };
+        },
         ProcessMatrixRedact: async (evt) => {
             MESSAGE_PROCCESS = "redacted";
         },
         UserSyncroniser: us,
+        edit: async (embedSet, opts, roomLookup, event) => {
+            MESSAGE_EDITED = true;
+        },
+        send: async (embedSet, opts, roomLookup, event) => {
+            MESSAGE_SENT = true;
+        },
         sendAsBot: async (msg, channel, event) => {
             STATE_EVENT_MSG = msg;
         },
@@ -205,10 +233,6 @@ function createMatrixEventProcessor() {
         },
     });
 
-    const store = {
-        removeEntriesByMatrixRoomId: () => Promise.resolve(),
-    };
-
     const processor = new (Proxyquire("../src/matrixeventprocessor", {
         "./util": {
             Util,
@@ -226,6 +250,66 @@ const mockChannel = new MockChannel();
 mockChannel.members.set("12345", new MockMember("12345", "testuser2"));
 
 describe("MatrixEventProcessor", () => {
+    describe("ProcessMsgEvent", () => {
+        it("Should send messages", async () => {
+            const { processor } = createMatrixEventProcessor();
+            const event = {
+                content: {
+                    body: "blah",
+                    msgtype: "m.text",
+                },
+                room_id: "!someroom:localhost",
+                sender: "@user:localhost",
+                type: "m.room.message",
+            } as any;
+            processor.HandleAttachment = async () => "";
+            processor.EventToEmbed = async (evt, chan) => {
+                return {
+                    messageEmbed: new Discord.RichEmbed(),
+                };
+            };
+            const room = { data: {
+                discord_channel: "1234",
+                discord_guild: "1234",
+            }} as any;
+            await processor.ProcessMsgEvent(event, room);
+            expect(MESSAGE_SENT).to.be.true;
+            expect(MESSAGE_EDITED).to.be.false;
+        });
+        it("Should eventually send edits", async () => {
+            const { processor } = createMatrixEventProcessor(1);
+            const event = {
+                content: {
+                    "body": "* blah",
+                    "m.new_content": {
+                        body: "blah",
+                        msgtype: "m.text",
+                    },
+                    "m.relates_to": {
+                        event_id: "editedevent",
+                        rel_type: "m.replace",
+                    },
+                    "msgtype": "m.text",
+                },
+                room_id: "!someroom:localhost",
+                sender: "@user:localhost",
+                type: "m.room.message",
+            } as any;
+            processor.HandleAttachment = async () => "";
+            processor.EventToEmbed = async (evt, chan) => {
+                return {
+                    messageEmbed: new Discord.RichEmbed(),
+                };
+            };
+            const room = { data: {
+                discord_channel: "1234",
+                discord_guild: "1234",
+            }} as any;
+            await processor.ProcessMsgEvent(event, room);
+            expect(MESSAGE_SENT).to.be.false;
+            expect(MESSAGE_EDITED).to.be.true;
+        });
+    });
     describe("ProcessStateEvent", () => {
         it("Should ignore unhandled states", async () => {
             const {processor} =  createMatrixEventProcessor();