diff --git a/briar-android/res/drawable-hdpi/content_attachment.png b/briar-android/res/drawable-hdpi/content_attachment.png
new file mode 100644
index 0000000000000000000000000000000000000000..53b963d54106ff032f364ac815f513ab91e9bd23
Binary files /dev/null and b/briar-android/res/drawable-hdpi/content_attachment.png differ
diff --git a/briar-android/res/drawable-mdpi/content_attachment.png b/briar-android/res/drawable-mdpi/content_attachment.png
new file mode 100644
index 0000000000000000000000000000000000000000..38ff9f853ce781299b92b471da4cb9d587100a66
Binary files /dev/null and b/briar-android/res/drawable-mdpi/content_attachment.png differ
diff --git a/briar-android/res/drawable-xhdpi/content_attachment.png b/briar-android/res/drawable-xhdpi/content_attachment.png
new file mode 100644
index 0000000000000000000000000000000000000000..1cffb3fbf2f1149821435933ea6a236ff2663ed5
Binary files /dev/null and b/briar-android/res/drawable-xhdpi/content_attachment.png differ
diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationAdapter.java b/briar-android/src/net/sf/briar/android/messages/ConversationAdapter.java
index 67c6c629b724593b71423efa56107ace831f40a3..31fdd1dcc84606d179b171ef7192393583a6f65a 100644
--- a/briar-android/src/net/sf/briar/android/messages/ConversationAdapter.java
+++ b/briar-android/src/net/sf/briar/android/messages/ConversationAdapter.java
@@ -45,6 +45,13 @@ implements OnItemClickListener {
 		else star.setImageResource(R.drawable.rating_not_important);
 		layout.addView(star);
 
+		if(!item.getContentType().equals("text/plain")) {
+			ImageView attachment = new ImageView(ctx);
+			attachment.setPadding(0, 5, 5, 5);
+			attachment.setImageResource(R.drawable.content_attachment);
+			layout.addView(attachment);
+		}
+
 		TextView subject = new TextView(ctx);
 		// Give me all the unused width
 		subject.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT,
diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java
index f09c7dabed6c714a23b804c9a0286079085d36e7..b54a41827e8eac042306b726b5c5e5c812924aee 100644
--- a/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java
+++ b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java
@@ -112,21 +112,21 @@ implements OnClickListener, DatabaseListener {
 						ContactId contactId = db.addContact("Carol");
 						// Insert some fake messages to and from the contact
 						Message m = messageFactory.createPrivateMessage(null,
-								"First message's subject is short",
-								"First message's body".getBytes("UTF-8"));
+								"text/plain",
+								"First message is short".getBytes("UTF-8"));
 						db.addLocalPrivateMessage(m, contactId);
 						db.setReadFlag(m.getId(), true);
 						db.setStarredFlag(m.getId(), true);
 						Thread.sleep(1000);
 						m = messageFactory.createPrivateMessage(m.getId(),
-								"Second message's subject is also short",
-								"Second message's body".getBytes("UTF-8"));
+								"image/jpeg", new byte[1000]);
 						db.receiveMessage(contactId, m);
 						Thread.sleep(1000);
 						m = messageFactory.createPrivateMessage(m.getId(),
-								"Third message's subject is quite long to test"
-								+ " line wrapping and exciting stuff like that",
-								"Third message's body".getBytes("UTF-8"));
+								"text/plain",
+								("Third message is quite long to test line"
+								+ " wrapping and subject line extraction and"
+								+ " all that fun stuff").getBytes("UTF-8"));
 						db.addLocalPrivateMessage(m, contactId);
 						db.setReadFlag(m.getId(), true);
 					}
diff --git a/briar-api/src/net/sf/briar/api/db/GroupMessageHeader.java b/briar-api/src/net/sf/briar/api/db/GroupMessageHeader.java
index af8add02b337bac51c6ced34c8614dd34c8e4425..543f34a939b1eaed183c11b3efc9c26ddf0fb52e 100644
--- a/briar-api/src/net/sf/briar/api/db/GroupMessageHeader.java
+++ b/briar-api/src/net/sf/briar/api/db/GroupMessageHeader.java
@@ -9,10 +9,10 @@ public class GroupMessageHeader extends MessageHeader {
 	private final GroupId groupId;
 	private final Author author;
 
-	public GroupMessageHeader(MessageId id, MessageId parent, String subject,
-			long timestamp, boolean read, boolean starred, GroupId groupId,
-			Author author) {
-		super(id, parent, subject, timestamp, read, starred);
+	public GroupMessageHeader(MessageId id, MessageId parent,
+			String contentType, String subject, long timestamp, boolean read,
+			boolean starred, GroupId groupId, Author author) {
+		super(id, parent, contentType, subject, timestamp, read, starred);
 		this.groupId = groupId;
 		this.author = author;
 	}
diff --git a/briar-api/src/net/sf/briar/api/db/MessageHeader.java b/briar-api/src/net/sf/briar/api/db/MessageHeader.java
index b1f11d1bd549b5add829b7dbd69af065b3121d24..2cbab3f51ce17268a48723f3ee44eefd757ef02f 100644
--- a/briar-api/src/net/sf/briar/api/db/MessageHeader.java
+++ b/briar-api/src/net/sf/briar/api/db/MessageHeader.java
@@ -5,14 +5,15 @@ import net.sf.briar.api.messaging.MessageId;
 public abstract class MessageHeader {
 
 	private final MessageId id, parent;
-	private final String subject;
+	private final String contentType, subject;
 	private final long timestamp;
 	private final boolean read, starred;
 
-	protected MessageHeader(MessageId id, MessageId parent, String subject,
-			long timestamp, boolean read, boolean starred) {
+	protected MessageHeader(MessageId id, MessageId parent, String contentType,
+			String subject, long timestamp, boolean read, boolean starred) {
 		this.id = id;
 		this.parent = parent;
+		this.contentType = contentType;
 		this.subject = subject;
 		this.timestamp = timestamp;
 		this.read = read;
@@ -32,6 +33,11 @@ public abstract class MessageHeader {
 		return parent;
 	}
 
+	/** Returns the message's content type. */
+	public String getContentType() {
+		return contentType;
+	}
+
 	/** Returns the message's subject line. */
 	public String getSubject() {
 		return subject;
diff --git a/briar-api/src/net/sf/briar/api/db/PrivateMessageHeader.java b/briar-api/src/net/sf/briar/api/db/PrivateMessageHeader.java
index 900c2cb2a92fa2c43c196594694ed8659d8381a2..af55211c66fb691f233ce82816525d03fca2ff29 100644
--- a/briar-api/src/net/sf/briar/api/db/PrivateMessageHeader.java
+++ b/briar-api/src/net/sf/briar/api/db/PrivateMessageHeader.java
@@ -8,10 +8,10 @@ public class PrivateMessageHeader extends MessageHeader {
 	private final ContactId contactId;
 	private final boolean incoming;
 
-	public PrivateMessageHeader(MessageId id, MessageId parent, String subject,
-			long timestamp, boolean read, boolean starred, ContactId contactId,
-			boolean incoming) {
-		super(id, parent, subject, timestamp, read, starred);
+	public PrivateMessageHeader(MessageId id, MessageId parent,
+			String contentType, String subject, long timestamp, boolean read,
+			boolean starred, ContactId contactId, boolean incoming) {
+		super(id, parent, contentType, subject, timestamp, read, starred);
 		this.contactId = contactId;
 		this.incoming = incoming;
 	}
diff --git a/briar-api/src/net/sf/briar/api/messaging/Message.java b/briar-api/src/net/sf/briar/api/messaging/Message.java
index f2aac57fba2adfc47b144e07a5954398075d780e..b48d54cc061380af1a8e9d4c5fdb7240a8e6847f 100644
--- a/briar-api/src/net/sf/briar/api/messaging/Message.java
+++ b/briar-api/src/net/sf/briar/api/messaging/Message.java
@@ -23,7 +23,14 @@ public interface Message {
 	 */
 	Author getAuthor();
 
-	/** Returns the message's subject line. */
+	/** Returns the message's content type. */
+	String getContentType();
+
+	/**
+	 * Returns the message's subject line, which is created from the first 50
+	 * bytes of the message body if the content type is text/plain, or is the
+	 * empty string otherwise.
+	 */
 	String getSubject();
 
 	/** Returns the timestamp created by the message's {@link Author}. */
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 25dee5e10c6b21e26a2fc4fc91679426bced186d..ade4acda4ed4040e5adedbb9592a5d4130719e47 100644
--- a/briar-api/src/net/sf/briar/api/messaging/MessageFactory.java
+++ b/briar-api/src/net/sf/briar/api/messaging/MessageFactory.java
@@ -7,27 +7,27 @@ import java.security.PrivateKey;
 public interface MessageFactory {
 
 	/** Creates a private message. */
-	Message createPrivateMessage(MessageId parent, String subject, byte[] body)
-			throws IOException, GeneralSecurityException;
+	Message createPrivateMessage(MessageId parent, String contentType,
+			byte[] body) throws IOException, GeneralSecurityException;
 
 	/** Creates an anonymous message to an unrestricted group. */
 	Message createAnonymousGroupMessage(MessageId parent, Group group,
-			String subject, byte[] body) throws IOException,
+			String contentType, byte[] body) throws IOException,
 			GeneralSecurityException;
 
 	/** Creates an anonymous message to a restricted group. */
 	Message createAnonymousGroupMessage(MessageId parent, Group group,
-			PrivateKey groupKey, String subject, byte[] body)
+			PrivateKey groupKey, String contentType, byte[] body)
 					throws IOException, GeneralSecurityException;
 
 	/** Creates a pseudonymous message to an unrestricted group. */
 	Message createPseudonymousMessage(MessageId parent, Group group,
-			Author author, PrivateKey authorKey, String subject, byte[] body)
-					throws IOException, GeneralSecurityException;
+			Author author, PrivateKey authorKey, String contentType,
+			byte[] body) throws IOException, GeneralSecurityException;
 
 	/** Creates a pseudonymous message to a restricted group. */
 	Message createPseudonymousMessage(MessageId parent, Group group,
 			PrivateKey groupKey, Author author, PrivateKey authorKey,
-			String subject, byte[] body) throws IOException,
+			String contentType, byte[] body) throws IOException,
 			GeneralSecurityException;
 }
diff --git a/briar-api/src/net/sf/briar/api/messaging/MessagingConstants.java b/briar-api/src/net/sf/briar/api/messaging/MessagingConstants.java
index 5f3f93ac28c2e8f1e7648791d801adeda74a0e79..4ddcedf2c5d6c87046b80ab78037f993e1470cc1 100644
--- a/briar-api/src/net/sf/briar/api/messaging/MessagingConstants.java
+++ b/briar-api/src/net/sf/briar/api/messaging/MessagingConstants.java
@@ -36,6 +36,9 @@ public interface MessagingConstants {
 	 */
 	int MAX_BODY_LENGTH = MAX_PACKET_LENGTH - 1024;
 
+	/** The maximum length of a message's content type in UTF-8 bytes. */
+	int MAX_CONTENT_TYPE_LENGTH = 50;
+
 	/** The maximum length of a message's subject line in UTF-8 bytes. */
 	int MAX_SUBJECT_LENGTH = 100;
 
diff --git a/briar-api/src/net/sf/briar/api/messaging/UnverifiedMessage.java b/briar-api/src/net/sf/briar/api/messaging/UnverifiedMessage.java
index cf1fcf2ce4e6356fd228bb4788f233e93d9d0d76..83c81e55558b401053461987f7cd14eea8672a0c 100644
--- a/briar-api/src/net/sf/briar/api/messaging/UnverifiedMessage.java
+++ b/briar-api/src/net/sf/briar/api/messaging/UnverifiedMessage.java
@@ -6,18 +6,19 @@ public class UnverifiedMessage {
 	private final MessageId parent;
 	private final Group group;
 	private final Author author;
-	private final String subject;
+	private final String contentType, subject;
 	private final long timestamp;
 	private final byte[] raw, authorSig, groupSig;
 	private final int bodyStart, bodyLength, signedByAuthor, signedByGroup;
 
 	public UnverifiedMessage(MessageId parent, Group group, Author author,
-			String subject, long timestamp, byte[] raw, byte[] authorSig,
-			byte[] groupSig, int bodyStart, int bodyLength, int signedByAuthor,
-			int signedByGroup) {
+			String contentType, String subject, long timestamp, byte[] raw,
+			byte[] authorSig, byte[] groupSig, int bodyStart, int bodyLength,
+			int signedByAuthor, int signedByGroup) {
 		this.parent = parent;
 		this.group = group;
 		this.author = author;
+		this.contentType = contentType;
 		this.subject = subject;
 		this.timestamp = timestamp;
 		this.raw = raw;
@@ -53,7 +54,16 @@ public class UnverifiedMessage {
 		return author;
 	}
 
-	/** Returns the message's subject line. */
+	/** Returns the message's content type. */
+	public String getContentType() {
+		return contentType;
+	}
+
+	/**
+	 * Returns the message's subject line, which is created from the first 50
+	 * bytes of the message body if the content type is text/plain, or is the
+	 * empty string otherwise.
+	 */
 	public String getSubject() {
 		return subject;
 	}
diff --git a/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java b/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java
index 299f52bd4e425961973e452e606bd14baefc12c5..888acb4642c86c94319149d7d429314eb3b05f4a 100644
--- a/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java
+++ b/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java
@@ -472,7 +472,7 @@ DatabaseCleaner.Callback {
 		if(m.getGroup() != null) throw new IllegalArgumentException();
 		if(m.getAuthor() != null) throw new IllegalArgumentException();
 		if(!db.addPrivateMessage(txn, m, c)) return false;
-		db.addStatus(txn, c, m.getId(), !incoming);
+		db.addStatus(txn, c, m.getId(), incoming);
 		// Count the bytes stored
 		synchronized(spaceLock) {
 			bytesStoredSinceLastCheck += m.getSerialised().length;
diff --git a/briar-core/src/net/sf/briar/db/JdbcDatabase.java b/briar-core/src/net/sf/briar/db/JdbcDatabase.java
index 45ec3fd7f32854c477796ad9c9f3f7970e84907d..4836072a9e41bdda73903083f5fc671cc704a405 100644
--- a/briar-core/src/net/sf/briar/db/JdbcDatabase.java
+++ b/briar-core/src/net/sf/briar/db/JdbcDatabase.java
@@ -125,6 +125,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 					+ " authorId HASH," // Null for private/anon messages
 					+ " authorName VARCHAR," // Null for private/anon messages
 					+ " authorKey VARCHAR," // Null for private/anon messages
+					+ " contentType VARCHAR NOT NULL,"
 					+ " subject VARCHAR NOT NULL,"
 					+ " timestamp BIGINT NOT NULL,"
 					+ " length INT NOT NULL,"
@@ -633,10 +634,10 @@ abstract class JdbcDatabase implements Database<Connection> {
 		PreparedStatement ps = null;
 		try {
 			String sql = "INSERT INTO messages (messageId, parentId, groupId,"
-					+ " authorId, authorName, authorKey, subject, timestamp,"
-					+ " length, bodyStart, bodyLength, raw, sendability, read,"
-					+ " starred)"
-					+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ZERO(),"
+					+ " authorId, authorName, authorKey, contentType, subject,"
+					+ " timestamp, length, bodyStart, bodyLength, raw,"
+					+ " sendability, read, starred)"
+					+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ZERO(),"
 					+ " FALSE, FALSE)";
 			ps = txn.prepareStatement(sql);
 			ps.setBytes(1, m.getId().getBytes());
@@ -653,13 +654,14 @@ abstract class JdbcDatabase implements Database<Connection> {
 				ps.setString(5, a.getName());
 				ps.setBytes(6, a.getPublicKey());
 			}
-			ps.setString(7, m.getSubject());
-			ps.setLong(8, m.getTimestamp());
+			ps.setString(7, m.getContentType());
+			ps.setString(8, m.getSubject());
+			ps.setLong(9, m.getTimestamp());
 			byte[] raw = m.getSerialised();
-			ps.setInt(9, raw.length);
-			ps.setInt(10, m.getBodyStart());
-			ps.setInt(11, m.getBodyLength());
-			ps.setBytes(12, raw);
+			ps.setInt(10, raw.length);
+			ps.setInt(11, m.getBodyStart());
+			ps.setInt(12, m.getBodyLength());
+			ps.setBytes(13, raw);
 			int affected = ps.executeUpdate();
 			if(affected != 1) throw new DbStateException();
 			ps.close();
@@ -707,22 +709,23 @@ abstract class JdbcDatabase implements Database<Connection> {
 		if(containsMessage(txn, m.getId())) return false;
 		PreparedStatement ps = null;
 		try {
-			String sql = "INSERT INTO messages (messageId, parentId, subject,"
-					+ " timestamp, length, bodyStart, bodyLength, raw,"
-					+ " contactId, read, starred)"
-					+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, FALSE, FALSE)";
+			String sql = "INSERT INTO messages (messageId, parentId,"
+					+ " contentType, subject, timestamp, length, bodyStart,"
+					+ " bodyLength, raw, contactId, read, starred)"
+					+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, FALSE, FALSE)";
 			ps = txn.prepareStatement(sql);
 			ps.setBytes(1, m.getId().getBytes());
 			if(m.getParent() == null) ps.setNull(2, BINARY);
 			else ps.setBytes(2, m.getParent().getBytes());
-			ps.setString(3, m.getSubject());
-			ps.setLong(4, m.getTimestamp());
+			ps.setString(3, m.getContentType());
+			ps.setString(4, m.getSubject());
+			ps.setLong(5, m.getTimestamp());
 			byte[] raw = m.getSerialised();
-			ps.setInt(5, raw.length);
-			ps.setInt(6, m.getBodyStart());
-			ps.setInt(7, m.getBodyLength());
-			ps.setBytes(8, raw);
-			ps.setInt(9, c.getInt());
+			ps.setInt(6, raw.length);
+			ps.setInt(7, m.getBodyStart());
+			ps.setInt(8, m.getBodyLength());
+			ps.setBytes(9, raw);
+			ps.setInt(10, c.getInt());
 			int affected = ps.executeUpdate();
 			if(affected != 1) throw new DbStateException();
 			ps.close();
@@ -1226,7 +1229,8 @@ abstract class JdbcDatabase implements Database<Connection> {
 		ResultSet rs = null;
 		try {
 			String sql = "SELECT messageId, parentId, authorId, authorName,"
-					+ " authorKey, subject, timestamp, read, starred"
+					+ " authorKey, contentType, subject, timestamp, read,"
+					+ " starred"
 					+ " FROM messages"
 					+ " WHERE groupId = ?";
 			ps = txn.prepareStatement(sql);
@@ -1246,12 +1250,13 @@ abstract class JdbcDatabase implements Database<Connection> {
 					byte[] authorKey = rs.getBytes(5);
 					author = new Author(authorId, authorName, authorKey);
 				}
-				String subject = rs.getString(6);
-				long timestamp = rs.getLong(7);
-				boolean read = rs.getBoolean(8);
-				boolean starred = rs.getBoolean(9);
-				headers.add(new GroupMessageHeader(id, parent, subject,
-						timestamp, read, starred, g, author));
+				String contentType = rs.getString(6);
+				String subject = rs.getString(7);
+				long timestamp = rs.getLong(8);
+				boolean read = rs.getBoolean(9);
+				boolean starred = rs.getBoolean(10);
+				headers.add(new GroupMessageHeader(id, parent, contentType,
+						subject, timestamp, read, starred, g, author));
 			}
 			rs.close();
 			ps.close();
@@ -1268,8 +1273,8 @@ abstract class JdbcDatabase implements Database<Connection> {
 		PreparedStatement ps = null;
 		ResultSet rs = null;
 		try {
-			String sql = "SELECT m.messageId, parentId, subject, timestamp,"
-					+ " m.contactId, read, starred, seen"
+			String sql = "SELECT m.messageId, parentId, contentType, subject,"
+					+ " timestamp, m.contactId, read, starred, seen"
 					+ " FROM messages AS m"
 					+ " JOIN statuses AS s"
 					+ " ON m.messageId = s.messageId"
@@ -1283,14 +1288,15 @@ abstract class JdbcDatabase implements Database<Connection> {
 				MessageId id = new MessageId(rs.getBytes(1));
 				byte[] b = rs.getBytes(2);
 				MessageId parent = b == null ? null : new MessageId(b);
-				String subject = rs.getString(3);
-				long timestamp = rs.getLong(4);
-				ContactId contactId = new ContactId(rs.getInt(5));
-				boolean read = rs.getBoolean(6);
-				boolean starred = rs.getBoolean(7);
-				boolean seen = rs.getBoolean(8);
-				headers.add(new PrivateMessageHeader(id, parent, subject,
-						timestamp, read, starred, contactId, !seen));
+				String contentType = rs.getString(3);
+				String subject = rs.getString(4);
+				long timestamp = rs.getLong(5);
+				ContactId contactId = new ContactId(rs.getInt(6));
+				boolean read = rs.getBoolean(7);
+				boolean starred = rs.getBoolean(8);
+				boolean seen = rs.getBoolean(9);
+				headers.add(new PrivateMessageHeader(id, parent, contentType,
+						subject, timestamp, read, starred, contactId, seen));
 			}
 			rs.close();
 			ps.close();
@@ -1307,8 +1313,8 @@ abstract class JdbcDatabase implements Database<Connection> {
 		PreparedStatement ps = null;
 		ResultSet rs = null;
 		try {
-			String sql = "SELECT m.messageId, parentId, subject, timestamp,"
-					+ " read, starred, seen"
+			String sql = "SELECT m.messageId, parentId, contentType, subject,"
+					+ " timestamp, read, starred, seen"
 					+ " FROM messages AS m"
 					+ " JOIN statuses AS s"
 					+ " ON m.messageId = s.messageId"
@@ -1323,13 +1329,14 @@ abstract class JdbcDatabase implements Database<Connection> {
 				MessageId id = new MessageId(rs.getBytes(1));
 				byte[] b = rs.getBytes(2);
 				MessageId parent = b == null ? null : new MessageId(b);
-				String subject = rs.getString(3);
-				long timestamp = rs.getLong(4);
-				boolean read = rs.getBoolean(5);
-				boolean starred = rs.getBoolean(6);
-				boolean seen = rs.getBoolean(7);
-				headers.add(new PrivateMessageHeader(id, parent, subject,
-						timestamp, read, starred, c, !seen));
+				String contentType = rs.getString(3);
+				String subject = rs.getString(4);
+				long timestamp = rs.getLong(5);
+				boolean read = rs.getBoolean(6);
+				boolean starred = rs.getBoolean(7);
+				boolean seen = rs.getBoolean(8);
+				headers.add(new PrivateMessageHeader(id, parent, contentType,
+						subject, timestamp, read, starred, c, seen));
 			}
 			rs.close();
 			ps.close();
diff --git a/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java b/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java
index 43d5f0f4b99a52e98f52e99f68f23402900199df..bf329c80c4621eab4a39d9ac420a72f28fcbd7a7 100644
--- a/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java
+++ b/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java
@@ -1,6 +1,7 @@
 package net.sf.briar.messaging;
 
 import static net.sf.briar.api.messaging.MessagingConstants.MAX_BODY_LENGTH;
+import static net.sf.briar.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH;
 import static net.sf.briar.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
 import static net.sf.briar.api.messaging.MessagingConstants.MAX_SIGNATURE_LENGTH;
 import static net.sf.briar.api.messaging.MessagingConstants.MAX_SUBJECT_LENGTH;
@@ -11,6 +12,9 @@ import static net.sf.briar.api.messaging.Types.MESSAGE;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
 import java.security.GeneralSecurityException;
 import java.security.PrivateKey;
 import java.security.SecureRandom;
@@ -40,6 +44,7 @@ class MessageFactoryImpl implements MessageFactory {
 	private final MessageDigest messageDigest;
 	private final WriterFactory writerFactory;
 	private final Clock clock;
+	private final CharsetDecoder decoder;
 
 	@Inject
 	MessageFactoryImpl(CryptoComponent crypto, WriterFactory writerFactory,
@@ -50,44 +55,46 @@ class MessageFactoryImpl implements MessageFactory {
 		messageDigest = crypto.getMessageDigest();
 		this.writerFactory = writerFactory;
 		this.clock = clock;
+		decoder = Charset.forName("UTF-8").newDecoder();
 	}
 
-	public Message createPrivateMessage(MessageId parent, String subject,
+	public Message createPrivateMessage(MessageId parent, String contentType,
 			byte[] body) throws IOException, GeneralSecurityException {
-		return createMessage(parent, null, null, null, null, subject, body);
+		return createMessage(parent, null, null, null, null, contentType, body);
 	}
 
 	public Message createAnonymousGroupMessage(MessageId parent, Group group,
-			String subject, byte[] body) throws IOException,
+			String contentType, byte[] body) throws IOException,
 			GeneralSecurityException {
-		return createMessage(parent, group, null, null, null, subject, body);
+		return createMessage(parent, group, null, null, null, contentType,
+				body);
 	}
 
 	public Message createAnonymousGroupMessage(MessageId parent, Group group,
-			PrivateKey groupKey, String subject, byte[] body)
+			PrivateKey groupKey, String contentType, byte[] body)
 					throws IOException, GeneralSecurityException {
-		return createMessage(parent, group, groupKey, null, null, subject,
+		return createMessage(parent, group, groupKey, null, null, contentType,
 				body);
 	}
 
 	public Message createPseudonymousMessage(MessageId parent, Group group,
-			Author author, PrivateKey authorKey, String subject, byte[] body)
+			Author author, PrivateKey authorKey, String contentType, byte[] body)
 					throws IOException, GeneralSecurityException {
-		return createMessage(parent, group, null, author, authorKey, subject,
-				body);
+		return createMessage(parent, group, null, author, authorKey,
+				contentType, body);
 	}
 
 	public Message createPseudonymousMessage(MessageId parent, Group group,
 			PrivateKey groupKey, Author author, PrivateKey authorKey,
-			String subject, byte[] body) throws IOException,
+			String contentType, byte[] body) throws IOException,
 			GeneralSecurityException {
 		return createMessage(parent, group, groupKey, author, authorKey,
-				subject, body);
+				contentType, body);
 	}
 
 	private Message createMessage(MessageId parent, Group group,
 			PrivateKey groupKey, Author author, PrivateKey authorKey,
-			String subject, byte[] body) throws IOException,
+			String contentType, byte[] body) throws IOException,
 			GeneralSecurityException {
 		// Validate the arguments
 		if((author == null) != (authorKey == null))
@@ -95,7 +102,7 @@ class MessageFactoryImpl implements MessageFactory {
 		if((group == null || group.getPublicKey() == null)
 				!= (groupKey == null))
 			throw new IllegalArgumentException();
-		if(subject.getBytes("UTF-8").length > MAX_SUBJECT_LENGTH)
+		if(contentType.getBytes("UTF-8").length > MAX_CONTENT_TYPE_LENGTH)
 			throw new IllegalArgumentException();
 		if(body.length > MAX_BODY_LENGTH)
 			throw new IllegalArgumentException();
@@ -127,7 +134,7 @@ class MessageFactoryImpl implements MessageFactory {
 		else writeGroup(w, group);
 		if(author == null) w.writeNull();
 		else writeAuthor(w, author);
-		w.writeString(subject);
+		w.writeString(contentType);
 		long timestamp = clock.currentTimeMillis();
 		w.writeInt64(timestamp);
 		byte[] salt = new byte[SALT_LENGTH];
@@ -158,7 +165,17 @@ class MessageFactoryImpl implements MessageFactory {
 		// Hash the message, including the signatures, to get the message ID
 		w.removeConsumer(digestingConsumer);
 		MessageId id = new MessageId(messageDigest.digest());
-		return new MessageImpl(id, parent, group, author, subject,
+		// If the content type is text/plain, extract a subject line
+		String subject;
+		if(contentType.equals("text/plain")) {
+			byte[] start = new byte[Math.min(MAX_SUBJECT_LENGTH, body.length)];
+			System.arraycopy(body, 0, start, 0, start.length);
+			decoder.reset();
+			subject = decoder.decode(ByteBuffer.wrap(start)).toString();
+		} else {
+			subject = "";
+		}
+		return new MessageImpl(id, parent, group, author, contentType, subject,
 				timestamp, out.toByteArray(), bodyStart, body.length);
 	}
 
diff --git a/briar-core/src/net/sf/briar/messaging/MessageImpl.java b/briar-core/src/net/sf/briar/messaging/MessageImpl.java
index 3472613223a9090e575442c51979b25d1eae5edd..4ff50f31024ae6b4a78a821fc211949108132607 100644
--- a/briar-core/src/net/sf/briar/messaging/MessageImpl.java
+++ b/briar-core/src/net/sf/briar/messaging/MessageImpl.java
@@ -12,14 +12,14 @@ class MessageImpl implements Message {
 	private final MessageId id, parent;
 	private final Group group;
 	private final Author author;
-	private final String subject;
+	private final String contentType, subject;
 	private final long timestamp;
 	private final byte[] raw;
 	private final int bodyStart, bodyLength;
 
 	public MessageImpl(MessageId id, MessageId parent, Group group,
-			Author author, String subject, long timestamp, byte[] raw,
-			int bodyStart, int bodyLength) {
+			Author author, String contentType, String subject, long timestamp,
+			byte[] raw, int bodyStart, int bodyLength) {
 		if(bodyStart + bodyLength > raw.length)
 			throw new IllegalArgumentException();
 		if(bodyLength > MAX_BODY_LENGTH)
@@ -28,6 +28,7 @@ class MessageImpl implements Message {
 		this.parent = parent;
 		this.group = group;
 		this.author = author;
+		this.contentType = contentType;
 		this.subject = subject;
 		this.timestamp = timestamp;
 		this.raw = raw;
@@ -51,6 +52,10 @@ class MessageImpl implements Message {
 		return author;
 	}
 
+	public String getContentType() {
+		return contentType;
+	}
+
 	public String getSubject() {
 		return subject;
 	}
diff --git a/briar-core/src/net/sf/briar/messaging/MessageReader.java b/briar-core/src/net/sf/briar/messaging/MessageReader.java
index 0345b70c6e34b3315ef0a53825a76c73a8d7f87f..de0bf74ac5b67b4087b27b2fdb04f165ddf1a504 100644
--- a/briar-core/src/net/sf/briar/messaging/MessageReader.java
+++ b/briar-core/src/net/sf/briar/messaging/MessageReader.java
@@ -1,6 +1,7 @@
 package net.sf.briar.messaging;
 
 import static net.sf.briar.api.messaging.MessagingConstants.MAX_BODY_LENGTH;
+import static net.sf.briar.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH;
 import static net.sf.briar.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
 import static net.sf.briar.api.messaging.MessagingConstants.MAX_SIGNATURE_LENGTH;
 import static net.sf.briar.api.messaging.MessagingConstants.MAX_SUBJECT_LENGTH;
@@ -8,6 +9,9 @@ import static net.sf.briar.api.messaging.MessagingConstants.SALT_LENGTH;
 import static net.sf.briar.api.messaging.Types.MESSAGE;
 
 import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
 
 import net.sf.briar.api.FormatException;
 import net.sf.briar.api.messaging.Author;
@@ -24,11 +28,13 @@ class MessageReader implements StructReader<UnverifiedMessage> {
 
 	private final StructReader<Group> groupReader;
 	private final StructReader<Author> authorReader;
+	private final CharsetDecoder decoder;
 
 	MessageReader(StructReader<Group> groupReader,
 			StructReader<Author> authorReader) {
 		this.groupReader = groupReader;
 		this.authorReader = authorReader;
+		decoder = Charset.forName("UTF-8").newDecoder();
 	}
 
 	public UnverifiedMessage readStruct(Reader r) throws IOException {
@@ -55,8 +61,8 @@ class MessageReader implements StructReader<UnverifiedMessage> {
 		Author author = null;
 		if(r.hasNull()) r.readNull();
 		else author = authorReader.readStruct(r);
-		// Read the subject
-		String subject = r.readString(MAX_SUBJECT_LENGTH);
+		// Read the content type
+		String contentType = r.readString(MAX_CONTENT_TYPE_LENGTH);
 		// Read the timestamp
 		long timestamp = r.readInt64();
 		if(timestamp < 0) throw new FormatException();
@@ -65,6 +71,16 @@ class MessageReader implements StructReader<UnverifiedMessage> {
 		if(salt.length < SALT_LENGTH) throw new FormatException();
 		// Read the message body
 		byte[] body = r.readBytes(MAX_BODY_LENGTH);
+		// If the content type is text/plain, extract a subject line
+		String subject;
+		if(contentType.equals("text/plain")) {
+			byte[] start = new byte[Math.min(MAX_SUBJECT_LENGTH, body.length)];
+			System.arraycopy(body, 0, start, 0, start.length);
+			decoder.reset();
+			subject = decoder.decode(ByteBuffer.wrap(start)).toString();
+		} else {
+			subject = "";
+		}
 		// Record the offset of the body within the message
 		int bodyStart = (int) counting.getCount() - body.length;
 		// Record the length of the data covered by the author's signature
@@ -83,8 +99,8 @@ class MessageReader implements StructReader<UnverifiedMessage> {
 		r.removeConsumer(counting);
 		r.removeConsumer(copying);
 		byte[] raw = copying.getCopy();
-		return new UnverifiedMessage(parent, group, author, subject, timestamp,
-				raw, authorSig, groupSig, bodyStart, body.length,
-				signedByAuthor, signedByGroup);
+		return new UnverifiedMessage(parent, group, author, contentType,
+				subject, timestamp, raw, authorSig, groupSig, bodyStart,
+				body.length, signedByAuthor, signedByGroup);
 	}
 }
diff --git a/briar-core/src/net/sf/briar/messaging/MessageVerifierImpl.java b/briar-core/src/net/sf/briar/messaging/MessageVerifierImpl.java
index e1dc4896e70b94ae2e22bb86692c2ee544451d0e..22abc26555f8a31628cbe869a13ef8997c93dbce 100644
--- a/briar-core/src/net/sf/briar/messaging/MessageVerifierImpl.java
+++ b/briar-core/src/net/sf/briar/messaging/MessageVerifierImpl.java
@@ -53,7 +53,8 @@ class MessageVerifierImpl implements MessageVerifier {
 			if(!signature.verify(m.getGroupSignature()))
 				throw new GeneralSecurityException();
 		}
-		return new MessageImpl(id, m.getParent(), group, author, m.getSubject(),
-				m.getTimestamp(), raw, m.getBodyStart(), m.getBodyLength());
+		return new MessageImpl(id, m.getParent(), group, author,
+				m.getContentType(), m.getSubject(), m.getTimestamp(), raw,
+				m.getBodyStart(), m.getBodyLength());
 	}
 }
diff --git a/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java b/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java
index 18aff79214164200eafc3c062c6bedb18a2c6083..e838923c98893c968b8790a1b6bbfb8cfc889ffa 100644
--- a/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java
+++ b/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java
@@ -70,7 +70,7 @@ public class ProtocolIntegrationTest extends BriarTestCase {
 	private final Group group, group1;
 	private final Message message, message1, message2, message3;
 	private final String authorName = "Alice";
-	private final String subject = "Hello";
+	private final String contentType = "text/plain";
 	private final String messageBody = "Hello world";
 	private final Collection<MessageId> messageIds;
 	private final TransportId transportId;
@@ -107,16 +107,16 @@ public class ProtocolIntegrationTest extends BriarTestCase {
 		// Create two messages to each group: one anonymous, one pseudonymous
 		MessageFactory messageFactory = i.getInstance(MessageFactory.class);
 		message = messageFactory.createAnonymousGroupMessage(null, group,
-				subject, messageBody.getBytes("UTF-8"));
+				contentType, messageBody.getBytes("UTF-8"));
 		message1 = messageFactory.createAnonymousGroupMessage(null, group1,
-				groupKeyPair.getPrivate(), subject,
+				groupKeyPair.getPrivate(), contentType,
 				messageBody.getBytes("UTF-8"));
 		message2 = messageFactory.createPseudonymousMessage(null, group,
-				author, authorKeyPair.getPrivate(), subject,
+				author, authorKeyPair.getPrivate(), contentType,
 				messageBody.getBytes("UTF-8"));
 		message3 = messageFactory.createPseudonymousMessage(null, group1,
 				groupKeyPair.getPrivate(), author, authorKeyPair.getPrivate(),
-				subject, messageBody.getBytes("UTF-8"));
+				contentType, messageBody.getBytes("UTF-8"));
 		messageIds = Arrays.asList(message.getId(), message1.getId(),
 				message2.getId(), message3.getId());
 		// Create some transport properties
diff --git a/briar-tests/src/net/sf/briar/TestMessage.java b/briar-tests/src/net/sf/briar/TestMessage.java
index 0c4ae532a9e201036ec24d5901456b977d0b4389..9a8283505eb4c893b50e30bbdbfc8cea89cdc27b 100644
--- a/briar-tests/src/net/sf/briar/TestMessage.java
+++ b/briar-tests/src/net/sf/briar/TestMessage.java
@@ -13,23 +13,26 @@ public class TestMessage implements Message {
 	private final MessageId id, parent;
 	private final Group group;
 	private final Author author;
-	private final String subject;
+	private final String contentType, subject;
 	private final long timestamp;
 	private final byte[] raw;
 	private final int bodyStart, bodyLength;
 
 	public TestMessage(MessageId id, MessageId parent, Group group,
-			Author author, String subject, long timestamp, byte[] raw) {
-		this(id, parent, group, author, subject, timestamp, raw, 0, raw.length);
+			Author author, String contentType, String subject, long timestamp,
+			byte[] raw) {
+		this(id, parent, group, author, contentType, subject, timestamp, raw, 0,
+				raw.length);
 	}
 
 	public TestMessage(MessageId id, MessageId parent, Group group,
-			Author author, String subject, long timestamp, byte[] raw,
-			int bodyStart, int bodyLength) {
+			Author author, String contentType, String subject, long timestamp,
+			byte[] raw, int bodyStart, int bodyLength) {
 		this.id = id;
 		this.parent = parent;
 		this.group = group;
 		this.author = author;
+		this.contentType = contentType;
 		this.subject = subject;
 		this.timestamp = timestamp;
 		this.raw = raw;
@@ -53,6 +56,10 @@ public class TestMessage implements Message {
 		return author;
 	}
 
+	public String getContentType() {
+		return contentType;
+	}
+
 	public String getSubject() {
 		return subject;
 	}
diff --git a/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java b/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java
index 1cf9044ffa54b389ef8759186aa3d3ac4b373d77..72958c9de3e0430e98de9794896500ce3e2b0e06 100644
--- a/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java
+++ b/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java
@@ -59,7 +59,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
 	protected final AuthorId authorId;
 	protected final Author author;
 	protected final MessageId messageId, messageId1;
-	protected final String subject;
+	protected final String contentType, subject;
 	protected final long timestamp;
 	protected final int size;
 	protected final byte[] raw;
@@ -80,14 +80,15 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
 		author = new Author(authorId, "Alice", new byte[60]);
 		messageId = new MessageId(TestUtils.getRandomId());
 		messageId1 = new MessageId(TestUtils.getRandomId());
+		contentType = "text/plain";
 		subject = "Foo";
 		timestamp = System.currentTimeMillis();
 		size = 1234;
 		raw = new byte[size];
-		message = new TestMessage(messageId, null, group, author, subject,
-				timestamp, raw);
-		privateMessage = new TestMessage(messageId, null, null, null, subject,
-				timestamp, raw);
+		message = new TestMessage(messageId, null, group, author, contentType,
+				subject, timestamp, raw);
+		privateMessage = new TestMessage(messageId, null, null, null,
+				contentType, subject, timestamp, raw);
 		transportId = new TransportId(TestUtils.getRandomId());
 		transportProperties = new TransportProperties(Collections.singletonMap(
 				"foo", "bar"));
diff --git a/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java b/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java
index ec00dd3f61c2d5f858832727622e8ee0c94bdcd0..31262080834f69942f71c45b16a5da37354dddcf 100644
--- a/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java
+++ b/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java
@@ -56,7 +56,7 @@ public class H2DatabaseTest extends BriarTestCase {
 	private final AuthorId authorId;
 	private final Author author;
 	private final MessageId messageId, messageId1;
-	private final String subject;
+	private final String contentType, subject;
 	private final long timestamp;
 	private final int size;
 	private final byte[] raw;
@@ -73,15 +73,16 @@ public class H2DatabaseTest extends BriarTestCase {
 		author = new Author(authorId, "Alice", new byte[60]);
 		messageId = new MessageId(TestUtils.getRandomId());
 		messageId1 = new MessageId(TestUtils.getRandomId());
+		contentType = "text/plain";
 		subject = "Foo";
 		timestamp = System.currentTimeMillis();
 		size = 1234;
 		raw = new byte[size];
 		random.nextBytes(raw);
-		message = new TestMessage(messageId, null, group, author, subject,
-				timestamp, raw);
-		privateMessage = new TestMessage(messageId1, null, null, null,
+		message = new TestMessage(messageId, null, group, author, contentType,
 				subject, timestamp, raw);
+		privateMessage = new TestMessage(messageId1, null, null, null,
+				contentType, subject, timestamp, raw);
 		transportId = new TransportId(TestUtils.getRandomId());
 		contactId = new ContactId(1);
 		contactName = "Alice";
@@ -552,7 +553,7 @@ public class H2DatabaseTest extends BriarTestCase {
 		Author author1 = new Author(authorId1, "Bob", new byte[60]);
 		MessageId messageId1 = new MessageId(TestUtils.getRandomId());
 		Message message1 = new TestMessage(messageId1, null, group, author1,
-				subject, timestamp, raw);
+				contentType, subject, timestamp, raw);
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -584,12 +585,12 @@ public class H2DatabaseTest extends BriarTestCase {
 		GroupId groupId1 = new GroupId(TestUtils.getRandomId());
 		Group group1 = new Group(groupId1, "Group name", null);
 		Message child1 = new TestMessage(childId1, messageId, group, author,
-				subject, timestamp, raw);
+				contentType, subject, timestamp, raw);
 		Message child2 = new TestMessage(childId2, messageId, group, author,
-				subject, timestamp, raw);
+				contentType, subject, timestamp, raw);
 		// The third child is in a different group
 		Message child3 = new TestMessage(childId3, messageId, group1, author,
-				subject, timestamp, raw);
+				contentType, subject, timestamp, raw);
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -620,7 +621,7 @@ public class H2DatabaseTest extends BriarTestCase {
 	public void testGetOldMessages() throws Exception {
 		MessageId messageId1 = new MessageId(TestUtils.getRandomId());
 		Message message1 = new TestMessage(messageId1, null, group, author,
-				subject, timestamp + 1000, raw);
+				contentType, subject, timestamp + 1000, raw);
 		Database<Connection> db = open(false);
 		Connection txn = db.startTransaction();
 
@@ -651,7 +652,7 @@ public class H2DatabaseTest extends BriarTestCase {
 		byte[] largeBody = new byte[ONE_MEGABYTE];
 		for(int i = 0; i < largeBody.length; i++) largeBody[i] = (byte) i;
 		Message message1 = new TestMessage(messageId, null, group, author,
-				subject, timestamp, largeBody);
+				contentType, subject, timestamp, largeBody);
 		Database<Connection> db = open(false);
 
 		// Sanity check: there should be enough space on disk for this test
@@ -1130,8 +1131,8 @@ public class H2DatabaseTest extends BriarTestCase {
 
 		// A message with no parent should return null
 		MessageId childId = new MessageId(TestUtils.getRandomId());
-		Message child = new TestMessage(childId, null, group, null, subject,
-				timestamp, raw);
+		Message child = new TestMessage(childId, null, group, null, contentType,
+				subject, timestamp, raw);
 		db.addGroupMessage(txn, child);
 		assertTrue(db.containsMessage(txn, childId));
 		assertNull(db.getGroupMessageParent(txn, childId));
@@ -1152,7 +1153,7 @@ public class H2DatabaseTest extends BriarTestCase {
 		MessageId childId = new MessageId(TestUtils.getRandomId());
 		MessageId parentId = new MessageId(TestUtils.getRandomId());
 		Message child = new TestMessage(childId, parentId, group, null,
-				subject, timestamp, raw);
+				contentType, subject, timestamp, raw);
 		db.addGroupMessage(txn, child);
 		assertTrue(db.containsMessage(txn, childId));
 		assertFalse(db.containsMessage(txn, parentId));
@@ -1178,9 +1179,9 @@ public class H2DatabaseTest extends BriarTestCase {
 		MessageId childId = new MessageId(TestUtils.getRandomId());
 		MessageId parentId = new MessageId(TestUtils.getRandomId());
 		Message child = new TestMessage(childId, parentId, group, null,
-				subject, timestamp, raw);
+				contentType, subject, timestamp, raw);
 		Message parent = new TestMessage(parentId, null, group1, null,
-				subject, timestamp, raw);
+				contentType, subject, timestamp, raw);
 		db.addGroupMessage(txn, child);
 		db.addGroupMessage(txn, parent);
 		assertTrue(db.containsMessage(txn, childId));
@@ -1203,7 +1204,7 @@ public class H2DatabaseTest extends BriarTestCase {
 		// A message with a private parent should return null
 		MessageId childId = new MessageId(TestUtils.getRandomId());
 		Message child = new TestMessage(childId, messageId1, group, null,
-				subject, timestamp, raw);
+				contentType, subject, timestamp, raw);
 		db.addGroupMessage(txn, child);
 		db.addPrivateMessage(txn, privateMessage, contactId);
 		assertTrue(db.containsMessage(txn, childId));
@@ -1227,9 +1228,9 @@ public class H2DatabaseTest extends BriarTestCase {
 		MessageId childId = new MessageId(TestUtils.getRandomId());
 		MessageId parentId = new MessageId(TestUtils.getRandomId());
 		Message child = new TestMessage(childId, parentId, group, null,
-				subject, timestamp, raw);
-		Message parent = new TestMessage(parentId, null, group, null, subject,
-				timestamp, raw);
+				contentType, subject, timestamp, raw);
+		Message parent = new TestMessage(parentId, null, group, null,
+				contentType, subject, timestamp, raw);
 		db.addGroupMessage(txn, child);
 		db.addGroupMessage(txn, parent);
 		assertTrue(db.containsMessage(txn, childId));
@@ -1252,9 +1253,9 @@ public class H2DatabaseTest extends BriarTestCase {
 		// Store a couple of messages
 		int bodyLength = raw.length - 20;
 		Message message1 = new TestMessage(messageId, null, group, null,
-				subject, timestamp, raw, 5, bodyLength);
+				contentType, subject, timestamp, raw, 5, bodyLength);
 		Message privateMessage1 = new TestMessage(messageId1, null, null,
-				null, subject, timestamp, raw, 10, bodyLength);
+				null, contentType, subject, timestamp, raw, 10, bodyLength);
 		db.addGroupMessage(txn, message1);
 		db.addPrivateMessage(txn, privateMessage1, contactId);
 
@@ -1294,7 +1295,7 @@ public class H2DatabaseTest extends BriarTestCase {
 		MessageId parentId = new MessageId(TestUtils.getRandomId());
 		long timestamp1 = System.currentTimeMillis();
 		Message message1 = new TestMessage(messageId1, parentId, group, author,
-				subject, timestamp1, raw);
+				contentType, subject, timestamp1, raw);
 		db.addGroupMessage(txn, message1);
 		// Mark one of the messages read
 		assertFalse(db.setReadFlag(txn, messageId, true));
@@ -1352,6 +1353,7 @@ public class H2DatabaseTest extends BriarTestCase {
 		assertEquals(m.getGroup().getId(), h.getGroupId());
 		if(m.getAuthor() == null) assertNull(h.getAuthor());
 		else assertEquals(m.getAuthor(), h.getAuthor());
+		assertEquals(m.getContentType(), h.getContentType());
 		assertEquals(m.getSubject(), h.getSubject());
 		assertEquals(m.getTimestamp(), h.getTimestamp());
 	}
@@ -1423,13 +1425,13 @@ public class H2DatabaseTest extends BriarTestCase {
 		db.addGroupMessage(txn, message);
 		MessageId messageId1 = new MessageId(TestUtils.getRandomId());
 		Message message1 = new TestMessage(messageId1, null, group, author,
-				subject, timestamp, raw);
+				contentType, subject, timestamp, raw);
 		db.addGroupMessage(txn, message1);
 
 		// Store one message in the second group
 		MessageId messageId2 = new MessageId(TestUtils.getRandomId());
 		Message message2 = new TestMessage(messageId2, null, group1, author,
-				subject, timestamp, raw);
+				contentType, subject, timestamp, raw);
 		db.addGroupMessage(txn, message2);
 
 		// Mark one of the messages in the first group read
diff --git a/briar-tests/src/net/sf/briar/messaging/ConstantsTest.java b/briar-tests/src/net/sf/briar/messaging/ConstantsTest.java
index f715b6f2c9995b8204cbe6a0c1b0c639abc1946e..76e4d6ccab4d30c30a1d38ba2f8a6f4b85f10496 100644
--- a/briar-tests/src/net/sf/briar/messaging/ConstantsTest.java
+++ b/briar-tests/src/net/sf/briar/messaging/ConstantsTest.java
@@ -8,7 +8,7 @@ import static net.sf.briar.api.messaging.MessagingConstants.MAX_PROPERTIES_PER_T
 import static net.sf.briar.api.messaging.MessagingConstants.MAX_PROPERTY_LENGTH;
 import static net.sf.briar.api.messaging.MessagingConstants.MAX_PUBLIC_KEY_LENGTH;
 import static net.sf.briar.api.messaging.MessagingConstants.MAX_SIGNATURE_LENGTH;
-import static net.sf.briar.api.messaging.MessagingConstants.MAX_SUBJECT_LENGTH;
+import static net.sf.briar.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH;
 import static net.sf.briar.api.messaging.MessagingConstants.MAX_SUBSCRIPTIONS;
 
 import java.io.ByteArrayOutputStream;
@@ -123,15 +123,16 @@ public class ConstantsTest extends BriarTestCase {
 				crypto.generateSignatureKeyPair().getPrivate();
 		PrivateKey authorPrivate =
 				crypto.generateSignatureKeyPair().getPrivate();
-		String subject = createRandomString(MAX_SUBJECT_LENGTH);
+		String contentType = createRandomString(MAX_CONTENT_TYPE_LENGTH);
 		byte[] body = new byte[MAX_BODY_LENGTH];
 		Message message = messageFactory.createPseudonymousMessage(parent,
-				group, groupPrivate, author, authorPrivate, subject, body);
+				group, groupPrivate, author, authorPrivate, contentType, body);
 		// Check the size of the serialised message
 		int length = message.getSerialised().length;
 		assertTrue(length > UniqueId.LENGTH + MAX_GROUP_NAME_LENGTH
 				+ MAX_PUBLIC_KEY_LENGTH + MAX_AUTHOR_NAME_LENGTH
-				+ MAX_PUBLIC_KEY_LENGTH + MAX_BODY_LENGTH);
+				+ MAX_PUBLIC_KEY_LENGTH + MAX_CONTENT_TYPE_LENGTH
+				+ MAX_BODY_LENGTH);
 		assertTrue(length <= MAX_PACKET_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 1257c0eccd66e5d4ceb08c4ed49d93fbe8f83d35..105518b8f53537393fde5308e8a1f4115ea6e357 100644
--- a/briar-tests/src/net/sf/briar/messaging/simplex/SimplexMessagingIntegrationTest.java
+++ b/briar-tests/src/net/sf/briar/messaging/simplex/SimplexMessagingIntegrationTest.java
@@ -112,10 +112,10 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
 		db.addEndpoint(ep);
 		km.endpointAdded(ep, initialSecret.clone());
 		// Send Bob a message
-		String subject = "Hello";
+		String contentType = "text/plain";
 		byte[] body = "Hi Bob!".getBytes("UTF-8");
 		MessageFactory messageFactory = alice.getInstance(MessageFactory.class);
-		Message message = messageFactory.createPrivateMessage(null, subject,
+		Message message = messageFactory.createPrivateMessage(null, contentType,
 				body);
 		db.addLocalPrivateMessage(message, contactId);
 		// Create an outgoing simplex connection