diff --git a/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java b/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java
index 44eb0aad30e4bef22adc6ef6536ba4f67ed7b039..aad72c171eed9cbd5b4c1711df9f3a640386f9d6 100644
--- a/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java
+++ b/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java
@@ -244,7 +244,8 @@ NoContactsDialog.Listener {
 				FragmentManager fm = getSupportFragmentManager();
 				noContactsDialog.show(fm, "NoContactsDialog");
 			} else {
-				startActivity(new Intent(this, WritePrivateMessageActivity.class));
+				startActivity(new Intent(this,
+						WritePrivateMessageActivity.class));
 			}
 		} else if(view == shareButton) {
 			String apkPath = getPackageCodePath();
diff --git a/briar-android/src/net/sf/briar/android/contact/ReadPrivateMessageActivity.java b/briar-android/src/net/sf/briar/android/contact/ReadPrivateMessageActivity.java
index 677b12db52346307ddd5d0b80b83488c713e225d..64927e0c699353b72bb89fc8803e25851fb84e25 100644
--- a/briar-android/src/net/sf/briar/android/contact/ReadPrivateMessageActivity.java
+++ b/briar-android/src/net/sf/briar/android/contact/ReadPrivateMessageActivity.java
@@ -60,6 +60,7 @@ implements OnClickListener {
 	@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
 	@Inject private volatile LifecycleManager lifecycleManager;
 	private volatile MessageId messageId = null;
+	private volatile long timestamp = -1;
 
 	@Override
 	public void onCreate(Bundle state) {
@@ -79,7 +80,7 @@ implements OnClickListener {
 		messageId = new MessageId(b);
 		String contentType = i.getStringExtra("net.sf.briar.CONTENT_TYPE");
 		if(contentType == null) throw new IllegalStateException();
-		long timestamp = i.getLongExtra("net.sf.briar.TIMESTAMP", -1);
+		timestamp = i.getLongExtra("net.sf.briar.TIMESTAMP", -1);
 		if(timestamp == -1) throw new IllegalStateException();
 
 		if(state == null) {
@@ -262,6 +263,7 @@ implements OnClickListener {
 			Intent i = new Intent(this, WritePrivateMessageActivity.class);
 			i.putExtra("net.sf.briar.CONTACT_ID", contactId.getInt());
 			i.putExtra("net.sf.briar.PARENT_ID", messageId.getBytes());
+			i.putExtra("net.sf.briar.TIMESTAMP", timestamp);
 			startActivity(i);
 			setResult(RESULT_REPLY);
 			finish();
diff --git a/briar-android/src/net/sf/briar/android/contact/WritePrivateMessageActivity.java b/briar-android/src/net/sf/briar/android/contact/WritePrivateMessageActivity.java
index 51e6720860cd710d2459952189d2d7bec61763d0..38891115c5ae22182d9042442c83cad48071a3b0 100644
--- a/briar-android/src/net/sf/briar/android/contact/WritePrivateMessageActivity.java
+++ b/briar-android/src/net/sf/briar/android/contact/WritePrivateMessageActivity.java
@@ -66,6 +66,7 @@ implements OnItemSelectedListener, OnClickListener {
 	private volatile LocalAuthor localAuthor = null;
 	private volatile ContactId contactId = null;
 	private volatile MessageId parentId = null;
+	private volatile long timestamp = -1;
 
 	@Override
 	public void onCreate(Bundle state) {
@@ -76,6 +77,7 @@ implements OnItemSelectedListener, OnClickListener {
 		if(id != -1) contactId = new ContactId(id);
 		byte[] b = i.getByteArrayExtra("net.sf.briar.PARENT_ID");
 		if(b != null) parentId = new MessageId(b);
+		timestamp = i.getLongExtra("net.sf.briar.TIMESTAMP", -1);
 
 		if(state != null) {
 			id = state.getInt("net.sf.briar.CONTACT_ID", -1);
@@ -262,8 +264,11 @@ implements OnItemSelectedListener, OnClickListener {
 			public void run() {
 				try {
 					lifecycleManager.waitForDatabase();
+					// Don't use an earlier timestamp than the parent
+					long time = System.currentTimeMillis();
+					time = Math.max(time, timestamp + 1);
 					Message m = messageFactory.createPrivateMessage(parentId,
-							"text/plain", body);
+							"text/plain", time, body);
 					long now = System.currentTimeMillis();
 					db.addLocalPrivateMessage(m, contactId);
 					long duration = System.currentTimeMillis() - now;
diff --git a/briar-android/src/net/sf/briar/android/groups/ReadGroupPostActivity.java b/briar-android/src/net/sf/briar/android/groups/ReadGroupPostActivity.java
index 3d9c94a130a7a6a1e1fa7bd1c718b9ad998dd4fa..34da4493e83b97f790f3bcfadab55c1817b31470 100644
--- a/briar-android/src/net/sf/briar/android/groups/ReadGroupPostActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/ReadGroupPostActivity.java
@@ -60,6 +60,7 @@ implements OnClickListener {
 	@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
 	@Inject private volatile LifecycleManager lifecycleManager;
 	private volatile MessageId messageId = null;
+	private volatile long timestamp = -1;
 
 	@Override
 	public void onCreate(Bundle state) {
@@ -78,7 +79,7 @@ implements OnClickListener {
 		String authorName = i.getStringExtra("net.sf.briar.AUTHOR_NAME");
 		String contentType = i.getStringExtra("net.sf.briar.CONTENT_TYPE");
 		if(contentType == null) throw new IllegalStateException();
-		long timestamp = i.getLongExtra("net.sf.briar.TIMESTAMP", -1);
+		timestamp = i.getLongExtra("net.sf.briar.TIMESTAMP", -1);
 		if(timestamp == -1) throw new IllegalStateException();
 
 		if(state == null) {
@@ -266,6 +267,7 @@ implements OnClickListener {
 			Intent i = new Intent(this, WriteGroupPostActivity.class);
 			i.putExtra("net.sf.briar.GROUP_ID", groupId.getBytes());
 			i.putExtra("net.sf.briar.PARENT_ID", messageId.getBytes());
+			i.putExtra("net.sf.briar.TIMESTAMP", timestamp);
 			startActivity(i);
 			setResult(RESULT_REPLY);
 			finish();
diff --git a/briar-android/src/net/sf/briar/android/groups/WriteGroupPostActivity.java b/briar-android/src/net/sf/briar/android/groups/WriteGroupPostActivity.java
index 8a94109454a50e4766ef2ca5b3d63c80fe6c25b7..4ea20fef52b92b22d34d9a59d1acd47f06359805 100644
--- a/briar-android/src/net/sf/briar/android/groups/WriteGroupPostActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/WriteGroupPostActivity.java
@@ -74,6 +74,7 @@ implements OnItemSelectedListener, OnClickListener {
 	private volatile LocalAuthor localAuthor = null;
 	private volatile Group group = null;
 	private volatile MessageId parentId = null;
+	private volatile long timestamp = -1;
 
 	@Override
 	public void onCreate(Bundle state) {
@@ -84,6 +85,7 @@ implements OnItemSelectedListener, OnClickListener {
 		if(b != null) groupId = new GroupId(b);
 		b = i.getByteArrayExtra("net.sf.briar.PARENT_ID");
 		if(b != null) parentId = new MessageId(b);
+		timestamp = i.getLongExtra("net.sf.briar.TIMESTAMP", -1);
 
 		if(state != null) {
 			b = state.getByteArray("net.sf.briar.LOCAL_AUTHOR_ID");
@@ -318,15 +320,18 @@ implements OnItemSelectedListener, OnClickListener {
 	// FIXME: This should happen on a CryptoExecutor thread
 	private Message createMessage(byte[] body) throws IOException,
 	GeneralSecurityException {
+		// Don't use an earlier timestamp than the parent
+		long time = System.currentTimeMillis();
+		time = Math.max(time, timestamp + 1);
 		if(localAuthor == null) {
 			return messageFactory.createAnonymousMessage(parentId, group,
-					"text/plain", body);
+					"text/plain", time, body);
 		} else {
 			KeyParser keyParser = crypto.getSignatureKeyParser();
 			byte[] authorKeyBytes = localAuthor.getPrivateKey();
 			PrivateKey authorKey = keyParser.parsePrivateKey(authorKeyBytes);
 			return messageFactory.createPseudonymousMessage(parentId,
-					group, localAuthor, authorKey, "text/plain", body);
+					group, localAuthor, authorKey, "text/plain", time, body);
 		}
 	}
 
diff --git a/briar-api/src/net/sf/briar/api/messaging/MessageFactory.java b/briar-api/src/net/sf/briar/api/messaging/MessageFactory.java
index 8ee5a07ca4aa8197e339fec733f6b42d332ec49f..6e4dc2dd2561c867c9f4852bb467e044139725d8 100644
--- a/briar-api/src/net/sf/briar/api/messaging/MessageFactory.java
+++ b/briar-api/src/net/sf/briar/api/messaging/MessageFactory.java
@@ -10,15 +10,17 @@ public interface MessageFactory {
 
 	/** Creates a private message. */
 	Message createPrivateMessage(MessageId parent, String contentType,
-			byte[] body) throws IOException, GeneralSecurityException;
+			long timestamp, byte[] body) throws IOException,
+			GeneralSecurityException;
 
 	/** Creates an anonymous group message. */
 	Message createAnonymousMessage(MessageId parent, Group group,
-			String contentType, byte[] body) throws IOException,
+			String contentType, long timestamp, byte[] body) throws IOException,
 			GeneralSecurityException;
 
 	/** Creates a pseudonymous group message. */
 	Message createPseudonymousMessage(MessageId parent, Group group,
 			Author author, PrivateKey privateKey, String contentType,
-			byte[] body) throws IOException, GeneralSecurityException;
+			long timestamp, byte[] body) throws IOException,
+			GeneralSecurityException;
 }
diff --git a/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java b/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java
index 0640a1354d4d51f3eeadc0aa7f6b5208492cbacd..6f4ab5b11bf8c73c2a3ee9c267151f5b24c8351d 100644
--- a/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java
+++ b/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java
@@ -17,7 +17,6 @@ import java.security.SecureRandom;
 import javax.inject.Inject;
 
 import net.sf.briar.api.Author;
-import net.sf.briar.api.clock.Clock;
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.crypto.MessageDigest;
 import net.sf.briar.api.crypto.PrivateKey;
@@ -39,39 +38,40 @@ class MessageFactoryImpl implements MessageFactory {
 	private final SecureRandom random;
 	private final MessageDigest messageDigest;
 	private final WriterFactory writerFactory;
-	private final Clock clock;
 
 	@Inject
-	MessageFactoryImpl(CryptoComponent crypto, WriterFactory writerFactory,
-			Clock clock) {
+	MessageFactoryImpl(CryptoComponent crypto, WriterFactory writerFactory) {
 		signature = crypto.getSignature();
 		random = crypto.getSecureRandom();
 		messageDigest = crypto.getMessageDigest();
 		this.writerFactory = writerFactory;
-		this.clock = clock;
 	}
 
 	public Message createPrivateMessage(MessageId parent, String contentType,
-			byte[] body) throws IOException, GeneralSecurityException {
-		return createMessage(parent, null, null, null, contentType, body);
+			long timestamp, byte[] body) throws IOException,
+			GeneralSecurityException {
+		return createMessage(parent, null, null, null, contentType, timestamp,
+				body);
 	}
 
 	public Message createAnonymousMessage(MessageId parent, Group group,
-			String contentType, byte[] body) throws IOException,
+			String contentType, long timestamp, byte[] body) throws IOException,
 			GeneralSecurityException {
-		return createMessage(parent, group, null, null, contentType, body);
+		return createMessage(parent, group, null, null, contentType, timestamp,
+				body);
 	}
 
 	public Message createPseudonymousMessage(MessageId parent, Group group,
 			Author author, PrivateKey privateKey, String contentType,
-			byte[] body) throws IOException, GeneralSecurityException {
+			long timestamp, byte[] body) throws IOException,
+			GeneralSecurityException {
 		return createMessage(parent, group, author, privateKey, contentType,
-				body);
+				timestamp, body);
 	}
 
 	private Message createMessage(MessageId parent, Group group, Author author,
-			PrivateKey privateKey, String contentType, byte[] body)
-					throws IOException, GeneralSecurityException {
+			PrivateKey privateKey, String contentType, long timestamp,
+			byte[] body) throws IOException, GeneralSecurityException {
 		// Validate the arguments
 		if((author == null) != (privateKey == null))
 			throw new IllegalArgumentException();
@@ -102,7 +102,6 @@ class MessageFactoryImpl implements MessageFactory {
 		if(author == null) w.writeNull();
 		else writeAuthor(w, author);
 		w.writeString(contentType);
-		long timestamp = clock.currentTimeMillis();
 		w.writeIntAny(timestamp);
 		byte[] salt = new byte[MESSAGE_SALT_LENGTH];
 		random.nextBytes(salt);
diff --git a/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java b/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java
index 2d4cbcb9503765fc9c8e62376951369cb40c8a8e..1a4b1c6590d79122443860e81997d2f0549faa74 100644
--- a/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java
+++ b/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java
@@ -71,6 +71,7 @@ public class ProtocolIntegrationTest extends BriarTestCase {
 	private final Message message, message1;
 	private final String authorName = "Alice";
 	private final String contentType = "text/plain";
+	private final long timestamp = System.currentTimeMillis();
 	private final String messageBody = "Hello world";
 	private final Collection<MessageId> messageIds;
 	private final TransportId transportId;
@@ -104,9 +105,9 @@ public class ProtocolIntegrationTest extends BriarTestCase {
 		// Create two messages to the group: one anonymous, one pseudonymous
 		MessageFactory messageFactory = i.getInstance(MessageFactory.class);
 		message = messageFactory.createAnonymousMessage(null, group,
-				contentType, messageBody.getBytes("UTF-8"));
+				contentType, timestamp, messageBody.getBytes("UTF-8"));
 		message1 = messageFactory.createPseudonymousMessage(null, group,
-				author, authorKeyPair.getPrivate(), contentType,
+				author, authorKeyPair.getPrivate(), contentType, timestamp,
 				messageBody.getBytes("UTF-8"));
 		messageIds = Arrays.asList(message.getId(), message1.getId());
 		// Create some transport properties
diff --git a/briar-tests/src/net/sf/briar/messaging/ConstantsTest.java b/briar-tests/src/net/sf/briar/messaging/ConstantsTest.java
index db00cdebd5c0ba34628bc595c946f61802e17b28..5534c73d95a3afd2193a196ea4ad9a602c1fa743 100644
--- a/briar-tests/src/net/sf/briar/messaging/ConstantsTest.java
+++ b/briar-tests/src/net/sf/briar/messaging/ConstantsTest.java
@@ -131,9 +131,10 @@ public class ConstantsTest extends BriarTestCase {
 		PrivateKey privateKey = crypto.generateSignatureKeyPair().getPrivate();
 		String contentType =
 				TestUtils.createRandomString(MAX_CONTENT_TYPE_LENGTH);
+		long timestamp = Long.MAX_VALUE;
 		byte[] body = new byte[MAX_BODY_LENGTH];
 		Message message = messageFactory.createPseudonymousMessage(parent,
-				group, author, privateKey, contentType, body);
+				group, author, privateKey, contentType, timestamp, body);
 		// Check the size of the serialised message
 		int length = message.getSerialised().length;
 		assertTrue(length > UniqueId.LENGTH + MAX_GROUP_NAME_LENGTH
diff --git a/briar-tests/src/net/sf/briar/messaging/simplex/SimplexMessagingIntegrationTest.java b/briar-tests/src/net/sf/briar/messaging/simplex/SimplexMessagingIntegrationTest.java
index 5a0cd6067998a1156ff48d0d1dc5a8bb0e3be4d4..5d0d325fb8cee45b55602f012e642e66f48145cc 100644
--- a/briar-tests/src/net/sf/briar/messaging/simplex/SimplexMessagingIntegrationTest.java
+++ b/briar-tests/src/net/sf/briar/messaging/simplex/SimplexMessagingIntegrationTest.java
@@ -123,10 +123,11 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
 		km.endpointAdded(ep, LATENCY, initialSecret.clone());
 		// Send Bob a message
 		String contentType = "text/plain";
+		long timestamp = System.currentTimeMillis();
 		byte[] body = "Hi Bob!".getBytes("UTF-8");
 		MessageFactory messageFactory = alice.getInstance(MessageFactory.class);
 		Message message = messageFactory.createPrivateMessage(null, contentType,
-				body);
+				timestamp, body);
 		db.addLocalPrivateMessage(message, contactId);
 		// Create an outgoing simplex connection
 		ByteArrayOutputStream out = new ByteArrayOutputStream();