diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/AbstractMailboxSession.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/AbstractMailboxSession.java
index 9461e2c91bf96321a99b6942b7521453f9111c46..5f27522d83073625084fe43f188c2f9193219cf8 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/AbstractMailboxSession.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/AbstractMailboxSession.java
@@ -3,6 +3,7 @@ package org.briarproject.bramble.mailbox;
 import org.briarproject.bramble.api.contact.ContactId;
 import org.briarproject.bramble.api.db.DbException;
 import org.briarproject.bramble.api.mailbox.MailboxConstants;
+import org.briarproject.bramble.api.sync.SyncSession;
 import org.briarproject.bramble.api.sync.SyncSessionFactory;
 import org.briarproject.bramble.api.transport.KeyManager;
 import org.briarproject.bramble.api.transport.StreamContext;
@@ -28,9 +29,10 @@ import java.util.logging.Logger;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
 import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
+import static org.briarproject.bramble.mailbox.protocol.MailboxMessage.TYPE.END;
 import static org.briarproject.bramble.util.LogUtils.logException;
 
-abstract class AbstractMailboxSession implements Runnable {
+abstract class AbstractMailboxSession {
 	private static final Logger LOG =
 			Logger.getLogger(AbstractMailboxSession.class.getName());
 	protected final Executor ioExecutor;
@@ -45,7 +47,7 @@ abstract class AbstractMailboxSession implements Runnable {
 
 	// Used to handle graceful session termination with END request
 	private AtomicBoolean remoteSessionFinished = new AtomicBoolean(false);
-	protected boolean running;
+	protected AtomicBoolean terminated = new AtomicBoolean(false);
 
 	public AbstractMailboxSession(Executor ioExecutor,
 			KeyManager keyManager,
@@ -71,8 +73,8 @@ abstract class AbstractMailboxSession implements Runnable {
 	/**
 	 * @return True if the session is running
 	 */
-	public boolean isRunning() {
-		return running;
+	public boolean isTerminated() {
+		return terminated.get();
 	}
 
 
@@ -86,16 +88,13 @@ abstract class AbstractMailboxSession implements Runnable {
 	 * Note: The stream is not encrypted, since the MailboxProtocol is responsible
 	 * for encrypting/decrypting requests
 	 */
-	protected void runDuplexOutgoingSession() {
+	protected SyncSession createDuplexOutgoingSession() {
 		MailboxSyncRequestWriter mbWriter =
 				new MailboxSyncRequestWriter(mailboxProtocol);
-		try {
-			syncSessionFactory
-					.createDuplexOutgoingSession(contactId, transportMaxLatency,
-							transportMaxIdleTime, mbWriter).run();
-		} catch (IOException e) {
-			logException(LOG, WARNING, e);
-		}
+
+		return syncSessionFactory
+				.createDuplexOutgoingSession(contactId, transportMaxLatency,
+						transportMaxIdleTime, mbWriter);
 	}
 
 	/**
@@ -133,12 +132,17 @@ abstract class AbstractMailboxSession implements Runnable {
 	 * Must be called if the session wants to receive and handle requests
 	 */
 	public void readRequests() {
-		while (!remoteSessionFinished.get()) {
+		while (!terminated.get()) {
 			try {
 				MailboxRequest req = mailboxProtocol.getNextRequest();
+				if (req.getType() == END) {
+					synchronized (remoteSessionFinished) {
+						remoteSessionFinished.set(true);
+					}
+					return;
+				}
 				ioExecutor.execute(() -> handleRequest(req));
-			} catch (IOException | InterruptedException e) {
-				// TODO: Handle interruptedException differently ?
+			} catch (InterruptedException e) {
 				logException(LOG, INFO, e);
 				return;
 			}
@@ -147,10 +151,11 @@ abstract class AbstractMailboxSession implements Runnable {
 
 	/**
 	 * Calls the appropriate handler for an incoming request
-	 *
+	 * <p>
 	 * NOTE: If a session does not support a specific request the appropriate
 	 * handler needs to be overwritten. This handler should throw a
 	 * {@link MailboxSessionHandleException}.
+	 *
 	 * @param req
 	 */
 	private void handleRequest(MailboxRequest req) {
@@ -167,9 +172,6 @@ abstract class AbstractMailboxSession implements Runnable {
 				case SYNC:
 					handleSync((MailboxRequestSync) req);
 					break;
-				case END:
-					handleEnd((MailboxRequestEnd) req);
-					break;
 				default:
 					throw new MailboxSessionHandleException(
 							"Unsupported request type");
@@ -194,17 +196,6 @@ abstract class AbstractMailboxSession implements Runnable {
 		}
 	}
 
-	/**
-	 * Marks the remote side of the session as finished. The session is active
-	 * until this side of the session calls {@link #endSession()}
-	 * @param req
-	 */
-	private void handleEnd(MailboxRequestEnd req) {
-		synchronized (remoteSessionFinished) {
-			remoteSessionFinished.set(true);
-		}
-	}
-
 	/**
 	 * Must be called once at the end of a AbstractMailboxSession to signal the end of
 	 * the session to the peer. This call blocks until the remote session
@@ -215,10 +206,13 @@ abstract class AbstractMailboxSession implements Runnable {
 
 		mailboxProtocol.writeRequest(new MailboxRequestEnd());
 
-		while (!remoteSessionFinished.get()) {
-			remoteSessionFinished.wait();
+		synchronized (remoteSessionFinished) {
+			while (!remoteSessionFinished.get()) {
+				remoteSessionFinished.wait();
+			}
 		}
-		running = false;
+
+		terminated.set(true);
 	}
 
 
@@ -262,10 +256,12 @@ abstract class AbstractMailboxSession implements Runnable {
 					keyManager.getStreamContext(MailboxConstants.ID, tag);
 
 			if (ctx == null) {
-				throw new IOException("Received stream with unrecognisable tag");
+				throw new IOException(
+						"Received stream with unrecognisable tag");
 			}
 
-			InputStream reader = streamReaderFactory.createStreamReader(in, ctx);
+			InputStream reader =
+					streamReaderFactory.createStreamReader(in, ctx);
 
 			syncSessionFactory.createIncomingSession(ctx.getContactId(), reader)
 					.run();
@@ -274,15 +270,16 @@ abstract class AbstractMailboxSession implements Runnable {
 		}
 	}
 
+	public void handleStore(MailboxRequestStore req)
+			throws MailboxSessionHandleException {
+		// TODO: mailbox storage for Mailbox implementation
+	}
+
+	public abstract void run() throws IOException;
+
 	protected class MailboxSessionHandleException extends Exception {
 		public MailboxSessionHandleException(String error) {
 			super(error);
 		}
 	}
-
-	public void handleStore(MailboxRequestStore req)
-			throws MailboxSessionHandleException{
-		// TODO: mailbox storage for Mailbox implementation
-	}
-
 }