diff --git a/src/bot.ts b/src/bot.ts
index deed4d7e4a38bd2d9b5a68eb405405d8e67935b9..83e1dfa7bb7cc7d1b10f0a04a281cb136cf9dd10 100644
--- a/src/bot.ts
+++ b/src/bot.ts
@@ -46,6 +46,9 @@ export class DiscordBot {
   private channelSync: ChannelSyncroniser;
   private roomHandler: MatrixRoomHandler;
 
+  /* Handles messages queued up to be sent to discord. */
+  private discordMessageQueue: { [channelId: string]: Promise<any> };
+
   constructor(config: DiscordBridgeConfig, store: DiscordStore, private provisioner: Provisioner) {
     this.config = config;
     this.store = store;
@@ -55,6 +58,7 @@ export class DiscordBot {
       new MessageProcessorOpts(this.config.bridge.domain, this),
     );
     this.presenceHandler = new PresenceHandler(this);
+    this.discordMessageQueue = {};
   }
 
   public setBridge(bridge: Bridge) {
@@ -103,11 +107,24 @@ export class DiscordBot {
       client.on("guildUpdate", (_, newGuild) => { this.channelSync.OnGuildUpdate(newGuild); });
       client.on("guildDelete", (guild) => { this.channelSync.OnGuildDelete(guild); });
 
-      client.on("messageDelete", (msg) => { this.DeleteDiscordMessage(msg); });
-      client.on("messageUpdate", (oldMessage, newMessage) => { this.OnMessageUpdate(oldMessage, newMessage); });
-      client.on("message", (msg) => { Bluebird.delay(MSG_PROCESS_DELAY).then(() => {
-          this.OnMessage(msg);
-        });
+      client.on("messageDelete", (msg: Discord.Message) => {
+          this.discordMessageQueue[msg.channel.id] = Promise.all([
+            this.discordMessageQueue[msg.channel.id] || Promise.resolve(),
+            Bluebird.delay(this.config.limits.discordSendDelay),
+        ]).then(() => this.DeleteDiscordMessage(msg));
+      });
+      client.on("messageUpdate", (oldMessage: Discord.Message, newMessage: Discord.Message) => {
+          this.discordMessageQueue[newMessage.channel.id] = Promise.all([
+            this.discordMessageQueue[newMessage.channel.id] || Promise.resolve(),
+            Bluebird.delay(this.config.limits.discordSendDelay),
+        ]).then(() => this.OnMessageUpdate(oldMessage, newMessage));
+      });
+      client.on("message", (msg: Discord.Message) => {
+        this.discordMessageQueue[msg.channel.id] = (async () => {
+            await (this.discordMessageQueue[msg.channel.id] || Promise.resolve());
+            await Bluebird.delay(this.config.limits.discordSendDelay);
+            await this.OnMessage(msg);
+        })();
       });
       const jsLog = new Log("discord.js");
 
@@ -486,7 +503,7 @@ export class DiscordBot {
     }
 
     // Update presence because sometimes discord misses people.
-    this.userSync.OnUpdateUser(msg.author).then(() => {
+    return this.userSync.OnUpdateUser(msg.author).then(() => {
       return this.channelSync.GetRoomIdsFromChannel(msg.channel).catch((err) => {
         log.verbose("No bridged rooms to send message to. Oh well.");
         return null;
@@ -576,18 +593,18 @@ export class DiscordBot {
     }
   }
 
-    private async DeleteDiscordMessage(msg: Discord.Message) {
-        log.info(`Got delete event for ${msg.id}`);
-        const storeEvent = await this.store.Get(DbEvent, {discord_id: msg.id});
-        if (!storeEvent.Result) {
-          log.warn(`Could not redact because the event was not in the store.`);
-          return;
-        }
-        while (storeEvent.Next()) {
-          log.info(`Deleting discord msg ${storeEvent.DiscordId}`);
-          const intent = this.GetIntentFromDiscordMember(msg.author);
-          const matrixIds = storeEvent.MatrixId.split(";");
-          await intent.getClient().redactEvent(matrixIds[1], matrixIds[0]);
-        }
+  private async DeleteDiscordMessage(msg: Discord.Message) {
+    log.info(`Got delete event for ${msg.id}`);
+    const storeEvent = await this.store.Get(DbEvent, {discord_id: msg.id});
+    if (!storeEvent.Result) {
+      log.warn(`Could not redact because the event was not in the store.`);
+      return;
     }
+    while (storeEvent.Next()) {
+      log.info(`Deleting discord msg ${storeEvent.DiscordId}`);
+      const intent = this.GetIntentFromDiscordMember(msg.author);
+      const matrixIds = storeEvent.MatrixId.split(";");
+      await intent.getClient().redactEvent(matrixIds[1], matrixIds[0]);
+    }
+  }
 }
diff --git a/src/config.ts b/src/config.ts
index bb35047882be464802f00288eeeb7d8d87ee0b5b..ca04a5ebe9a4158267aede7f8c73bc23915c032f 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -78,6 +78,7 @@ class DiscordBridgeConfigChannelDeleteOptions {
 
 class DiscordBridgeConfigLimits {
   public roomGhostJoinDelay: number = 6000;
+  public discordSendDelay: number = 750;
 }
 
 export class LoggingFile {
diff --git a/test/mocks/discordclient.ts b/test/mocks/discordclient.ts
index d431ebf1dd0b0a768d691aeeac08560148ef8a24..20da7ba2e72ef8d2dcbb5b801e2b5acfcce10b44 100644
--- a/test/mocks/discordclient.ts
+++ b/test/mocks/discordclient.ts
@@ -1,12 +1,13 @@
 import {MockCollection} from "./collection";
 import {MockGuild} from "./guild";
 import {MockUser} from "./user";
+import { EventEmitter } from "events";
 
 export class MockDiscordClient {
   public guilds = new MockCollection<string, MockGuild>();
   public user: MockUser;
   private testLoggedIn: boolean = false;
-  private testCallbacks: Map<string, () => void> = new Map();
+  private testCallbacks: Map<string, (...data: any[]) => void> = new Map();
 
   constructor() {
     const channels = [
@@ -30,10 +31,14 @@ export class MockDiscordClient {
     this.user = new MockUser("12345");
   }
 
-  public on(event: string, callback: () => void) {
+  public on(event: string, callback: (...data: any[]) => void) {
       this.testCallbacks.set(event, callback);
   }
 
+  public emit(event: string, ...data: any[]) {
+      return this.testCallbacks.get(event).apply(this, data);
+  }
+
   public async login(token: string): Promise<void> {
     if (token !== "passme") {
         throw new Error("Mock Discord Client only logins with the token 'passme'");
diff --git a/test/mocks/discordclientfactory.ts b/test/mocks/discordclientfactory.ts
index 99bb5b2e47e6fd4ffc5becc86a9e5f1a6082cff6..5248acbffdf67cdb359bf65c9ce9fafc48561fa1 100644
--- a/test/mocks/discordclientfactory.ts
+++ b/test/mocks/discordclientfactory.ts
@@ -1,6 +1,7 @@
 import {MockDiscordClient} from "./discordclient";
 
 export class DiscordClientFactory {
+  private botClient: MockDiscordClient = null;
   constructor(config: any, store: any) {
     ;
   }
@@ -10,6 +11,9 @@ export class DiscordClientFactory {
   }
 
   public getClient(userId?: string): Promise<MockDiscordClient> {
-    return Promise.resolve(new MockDiscordClient());
+    if (userId == null && !this.botClient){
+        this.botClient = new MockDiscordClient();
+    }
+    return Promise.resolve(this.botClient);
   }
 }
diff --git a/test/test_discordbot.ts b/test/test_discordbot.ts
index 1233fb299e4437b5b30d6de931c14851c4bf703a..aa21e3a19b6f4bba231572dccd0d8384b2cda594 100644
--- a/test/test_discordbot.ts
+++ b/test/test_discordbot.ts
@@ -7,6 +7,8 @@ import { Log } from "../src/log";
 import { MessageProcessorMatrixResult } from "../src/messageprocessor";
 import { MockGuild } from "./mocks/guild";
 import { MockMember } from "./mocks/member";
+import { DiscordBot } from "../src/bot";
+import { MockDiscordClient } from "./mocks/discordclient";
 
 Chai.use(ChaiAsPromised);
 
@@ -52,6 +54,9 @@ describe("DiscordBot", () => {
     bridge: {
         domain: "localhost",
     },
+    limits: {
+        discordSendDelay: 50,
+    }
   };
   describe("run()", () => {
     it("should resolve when ready.", () => {
@@ -140,6 +145,28 @@ describe("DiscordBot", () => {
       });
     });
   });
+  describe("event:message", () => {
+    it("should delay messages so they arrive in order", async () => {
+        discordBot = new modDiscordBot.DiscordBot(
+          config,
+          mockBridge,
+      );
+      let expected = 0;
+      discordBot.OnMessage = (msg: any) => {
+          assert.equal(msg.n, expected);
+          expected++;
+          return Promise.resolve()
+      };
+      const client: MockDiscordClient = (await discordBot.ClientFactory.getClient()) as MockDiscordClient;
+      discordBot.setBridge(mockBridge);
+      await discordBot.run();
+      // Send delay of 50ms, 2 seconds / 50ms - 5 for safety.
+      for (let i = 0; i < (2000 / 50) - 5; i++) {
+          client.emit("message", { n: i, channel: { id: 123} });
+      }
+      await discordBot.discordMessageQueue[123];
+    });
+  });
 
   // describe("ProcessMatrixMsgEvent()", () => {
   //