diff --git a/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java
index a052e7393423b772b928f17bf217c9b2b6c50b96..7a9652a610f22ff4a994655458cdfbf33ff6cf3d 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java
@@ -2,6 +2,7 @@ package org.briarproject.briar.android.introduction;
 
 import android.content.Context;
 import android.os.Bundle;
+import android.support.annotation.Nullable;
 import android.support.v7.app.ActionBar;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
@@ -32,6 +33,7 @@ import im.delight.android.identicons.IdenticonDrawable;
 
 import static android.app.Activity.RESULT_OK;
 import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
 import static android.widget.Toast.LENGTH_SHORT;
 import static java.util.logging.Level.WARNING;
 import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_REQUEST_MESSAGE_LENGTH;
@@ -124,14 +126,15 @@ public class IntroductionMessageFragment extends BaseFragment
 						new ContactId(contactId1));
 				Contact c2 = contactManager.getContact(
 						new ContactId(contactId2));
-				setUpViews(c1, c2);
+				boolean possible = introductionManager.canIntroduce(c1, c2);
+				setUpViews(c1, c2, possible);
 			} catch (DbException e) {
 				if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
 			}
 		});
 	}
 
-	private void setUpViews(Contact c1, Contact c2) {
+	private void setUpViews(Contact c1, Contact c2, boolean possible) {
 		introductionActivity.runOnUiThreadUnlessDestroyed(() -> {
 			contact1 = c1;
 			contact2 = c2;
@@ -146,13 +149,22 @@ public class IntroductionMessageFragment extends BaseFragment
 			ui.contactName1.setText(c1.getAuthor().getName());
 			ui.contactName2.setText(c2.getAuthor().getName());
 
-			// set button action
-			ui.message.setListener(IntroductionMessageFragment.this);
-
-			// hide progress bar and show views
+			// hide progress bar
 			ui.progressBar.setVisibility(GONE);
-			ui.message.setSendButtonEnabled(true);
-			ui.message.showSoftKeyboard();
+
+			if (possible) {
+				// set button action
+				ui.message.setListener(IntroductionMessageFragment.this);
+
+				// show views
+				ui.notPossible.setVisibility(GONE);
+				ui.message.setVisibility(VISIBLE);
+				ui.message.setSendButtonEnabled(true);
+				ui.message.showSoftKeyboard();
+			} else {
+				ui.notPossible.setVisibility(VISIBLE);
+				ui.message.setVisibility(GONE);
+			}
 		});
 	}
 
@@ -174,7 +186,8 @@ public class IntroductionMessageFragment extends BaseFragment
 		ui.message.setSendButtonEnabled(false);
 
 		String msg = ui.message.getText().toString();
-		msg = StringUtils.truncateUtf8(msg, MAX_REQUEST_MESSAGE_LENGTH);
+		if (msg.equals("")) msg = null;
+		else msg = StringUtils.truncateUtf8(msg, MAX_REQUEST_MESSAGE_LENGTH);
 		makeIntroduction(contact1, contact2, msg);
 
 		// don't wait for the introduction to be made before finishing activity
@@ -183,7 +196,8 @@ public class IntroductionMessageFragment extends BaseFragment
 		introductionActivity.supportFinishAfterTransition();
 	}
 
-	private void makeIntroduction(Contact c1, Contact c2, String msg) {
+	private void makeIntroduction(Contact c1, Contact c2,
+			@Nullable String msg) {
 		introductionActivity.runOnDbThread(() -> {
 			// actually make the introduction
 			try {
@@ -207,6 +221,7 @@ public class IntroductionMessageFragment extends BaseFragment
 		private final ProgressBar progressBar;
 		private final CircleImageView avatar1, avatar2;
 		private final TextView contactName1, contactName2;
+		private final TextView notPossible;
 		private final TextInputView message;
 
 		private ViewHolder(View v) {
@@ -215,6 +230,7 @@ public class IntroductionMessageFragment extends BaseFragment
 			avatar2 = v.findViewById(R.id.avatarContact2);
 			contactName1 = v.findViewById(R.id.nameContact1);
 			contactName2 = v.findViewById(R.id.nameContact2);
+			notPossible = v.findViewById(R.id.introductionNotPossibleView);
 			message = v.findViewById(R.id.introductionMessageView);
 		}
 	}
diff --git a/briar-android/src/main/res/layout/introduction_message.xml b/briar-android/src/main/res/layout/introduction_message.xml
index e78e1c63980169f266bef00394d1232bdf245bd4..0cdc34ba86a400842a912bc59e6367b32c6095df 100644
--- a/briar-android/src/main/res/layout/introduction_message.xml
+++ b/briar-android/src/main/res/layout/introduction_message.xml
@@ -94,13 +94,25 @@
 			android:layout_gravity="center"
 			tools:visibility="gone"/>
 
+		<TextView
+			android:id="@+id/introductionNotPossibleView"
+			android:layout_width="match_parent"
+			android:layout_height="wrap_content"
+			android:layout_margin="@dimen/margin_activity_horizontal"
+			android:text="@string/introduction_not_possible"
+			android:textSize="@dimen/text_size_large"
+			android:visibility="gone"
+			tools:visibility="visible"/>
+
 		<org.briarproject.briar.android.view.LargeTextInputView
 			android:id="@+id/introductionMessageView"
 			android:layout_width="match_parent"
 			android:layout_height="wrap_content"
+			android:visibility="gone"
 			app:buttonText="@string/introduction_button"
 			app:hint="@string/introduction_message_hint"
-			app:maxLines="5"/>
+			app:maxLines="5"
+			tools:visibility="visible"/>
 
 	</LinearLayout>
 </ScrollView>
\ No newline at end of file
diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml
index d4b40f5bb8636cadbb67b1b4fe315222e0fbe11c..38b04cd534ba1ac46342e839d5f61b8e7d90514b 100644
--- a/briar-android/src/main/res/values/strings.xml
+++ b/briar-android/src/main/res/values/strings.xml
@@ -144,6 +144,7 @@
 	<string name="introduction_onboarding_title">Introduce your contacts</string>
 	<string name="introduction_onboarding_text">You can introduce your contacts to each other, so they don\'t need to meet in person to connect on Briar.</string>
 	<string name="introduction_activity_title">Select Contact</string>
+	<string name="introduction_not_possible">You already have one introduction in progress with these contacts. Please allow for this to finish first. If you or your contacts are rarely online, this can take some time.</string>
 	<string name="introduction_message_title">Introduce Contacts</string>
 	<string name="introduction_message_hint">Add a message (optional)</string>
 	<string name="introduction_button">Make Introduction</string>
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java
index 15936e8ad84f9fad746902d0ac88293a01b0495f..813b039de32f72b1e9ade352e11853ac02fb977b 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java
@@ -25,6 +25,8 @@ public interface IntroductionManager extends ConversationClient {
 	 */
 	int CLIENT_VERSION = 1;
 
+	boolean canIntroduce(Contact c1, Contact c2) throws DbException;
+
 	/**
 	 * Sends two initial introduction messages.
 	 */
diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java
index 0e4639f7fbafbb460a4997fbf7069d4e4827974c..bfb81a4b8d738e75536c45426154812d41a9622c 100644
--- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java
@@ -47,6 +47,7 @@ import javax.inject.Inject;
 import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
 import static org.briarproject.briar.api.introduction.Role.INTRODUCEE;
 import static org.briarproject.briar.api.introduction.Role.INTRODUCER;
+import static org.briarproject.briar.introduction.IntroducerState.START;
 import static org.briarproject.briar.introduction.IntroductionConstants.GROUP_KEY_CONTACT_ID;
 import static org.briarproject.briar.introduction.MessageType.ABORT;
 import static org.briarproject.briar.introduction.MessageType.ACCEPT;
@@ -267,6 +268,28 @@ class IntroductionManagerImpl extends ConversationClientImpl
 		}
 	}
 
+	@Override
+	public boolean canIntroduce(Contact c1, Contact c2) throws DbException {
+		Transaction txn = db.startTransaction(true);
+		try {
+			// Look up the session, if there is one
+			Author introducer = identityManager.getLocalAuthor(txn);
+			SessionId sessionId =
+					crypto.getSessionId(introducer, c1.getAuthor(),
+							c2.getAuthor());
+			StoredSession ss = getSession(txn, sessionId);
+			if (ss == null) return true;
+			IntroducerSession session =
+					sessionParser.parseIntroducerSession(ss.bdfSession);
+			if (session.getState() == START) return true;
+		} catch (FormatException e) {
+			throw new DbException(e);
+		} finally {
+			db.endTransaction(txn);
+		}
+		return false;
+	}
+
 	@Override
 	public void makeIntroduction(Contact c1, Contact c2, @Nullable String msg,
 			long timestamp) throws DbException {
@@ -398,12 +421,11 @@ class IntroductionManagerImpl extends ConversationClientImpl
 		Role role = sessionParser.getRole(bdfSession);
 		SessionId sessionId;
 		Author author;
-		LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
 		if (role == INTRODUCER) {
 			IntroducerSession session =
 					sessionParser.parseIntroducerSession(bdfSession);
 			sessionId = session.getSessionId();
-			if (localAuthor.equals(session.getIntroducee1().author)) {
+			if (contactGroupId.equals(session.getIntroducee1().groupId)) {
 				author = session.getIntroducee2().author;
 			} else {
 				author = session.getIntroducee1().author;
@@ -419,6 +441,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
 		if (msg == null || body == null) throw new AssertionError();
 		RequestMessage rm = messageParser.parseRequestMessage(msg, body);
 		String message = rm.getMessage();
+		LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
 		boolean contactExists = contactManager
 				.contactExists(txn, rm.getAuthor().getId(),
 						localAuthor.getId());
diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java
index 6d13b80f197a56bb9ee04f3920a2bf53355afbad..880210039adb938baefdba797482b1358373d40e 100644
--- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java
@@ -23,6 +23,7 @@ import org.briarproject.bramble.api.sync.Group;
 import org.briarproject.bramble.api.sync.Message;
 import org.briarproject.bramble.api.sync.MessageId;
 import org.briarproject.bramble.test.TestDatabaseModule;
+import org.briarproject.briar.api.client.ProtocolStateException;
 import org.briarproject.briar.api.client.SessionId;
 import org.briarproject.briar.api.introduction.IntroductionManager;
 import org.briarproject.briar.api.introduction.IntroductionMessage;
@@ -446,6 +447,26 @@ public class IntroductionIntegrationTest
 		assertFalse(listener2.aborted);
 	}
 
+	@Test(expected = ProtocolStateException.class)
+	public void testDoubleIntroduction() throws Exception {
+		// we can make an introduction
+		assertTrue(introductionManager0
+				.canIntroduce(contact1From0, contact2From0));
+
+		// make the introduction
+		long time = clock.currentTimeMillis();
+		introductionManager0
+				.makeIntroduction(contact1From0, contact2From0, null, time);
+
+		// no more introduction allowed while the existing one is in progress
+		assertFalse(introductionManager0
+				.canIntroduce(contact1From0, contact2From0));
+
+		// try it anyway and fail
+		introductionManager0
+				.makeIntroduction(contact1From0, contact2From0, null, time);
+	}
+
 	@Test
 	public void testIntroducerRemovedCleanup() throws Exception {
 		addListeners(true, true);