diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java
index e86153d78d2b2b55283d0d54465f69228159d848..372421364dcf80d431d149a91d45816e8e20b339 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java
@@ -306,15 +306,6 @@ public interface DatabaseComponent {
 	Collection<MessageId> getMessagesToShare(Transaction txn)
 			throws DbException;
 
-	/**
-	 * Returns the message with the given ID, in serialised form.
-	 * <p/>
-	 * Read-only.
-	 *
-	 * @throws MessageDeletedException if the message has been deleted
-	 */
-	byte[] getRawMessage(Transaction txn, MessageId m) throws DbException;
-
 	/**
 	 * Returns the metadata for all delivered messages in the given group.
 	 * <p/>
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/client/ClientHelperImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/client/ClientHelperImpl.java
index e457865243505d32367b192bb9c60ac4fc28caac..62ff284dd0ef82f8be259860d46151c5cb0bbc7e 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/client/ClientHelperImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/client/ClientHelperImpl.java
@@ -127,7 +127,7 @@ class ClientHelperImpl implements ClientHelper {
 
 	@Override
 	public Message getMessage(Transaction txn, MessageId m) throws DbException {
-		return messageFactory.createMessage(m, db.getRawMessage(txn, m));
+		return db.getMessage(txn, m);
 	}
 
 	@Override
@@ -147,7 +147,7 @@ class ClientHelperImpl implements ClientHelper {
 	@Override
 	public BdfList getMessageAsList(Transaction txn, MessageId m)
 			throws DbException, FormatException {
-		byte[] raw = db.getRawMessage(txn, m);
+		byte[] raw = db.getMessage(txn, m).getRaw();
 		return toList(raw, MESSAGE_HEADER_LENGTH,
 				raw.length - MESSAGE_HEADER_LENGTH);
 	}
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java
index 4023c4c969833708a5c956ee120f7545c0611758..edeade4eeea23c37ba62e97ce2f1fb4b0d6946c3 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java
@@ -496,15 +496,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 		return db.getMessagesToShare(txn);
 	}
 
-	@Override
-	public byte[] getRawMessage(Transaction transaction, MessageId m)
-			throws DbException {
-		T txn = unbox(transaction);
-		if (!db.containsMessage(txn, m))
-			throw new NoSuchMessageException();
-		return db.getRawMessage(txn, m);
-	}
-
 	@Override
 	public Map<MessageId, Metadata> getMessageMetadata(Transaction transaction,
 			GroupId g) throws DbException {
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/sync/ValidationManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/sync/ValidationManagerImpl.java
index 64edbbb973d6297858af8604cafdf3d013d947f2..99d3335e7aa99122ef394b4dc6af765176bb4e12 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/sync/ValidationManagerImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/sync/ValidationManagerImpl.java
@@ -16,7 +16,6 @@ import org.briarproject.bramble.api.sync.Group;
 import org.briarproject.bramble.api.sync.InvalidMessageException;
 import org.briarproject.bramble.api.sync.Message;
 import org.briarproject.bramble.api.sync.MessageContext;
-import org.briarproject.bramble.api.sync.MessageFactory;
 import org.briarproject.bramble.api.sync.MessageId;
 import org.briarproject.bramble.api.sync.ValidationManager;
 import org.briarproject.bramble.api.sync.event.MessageAddedEvent;
@@ -52,7 +51,6 @@ class ValidationManagerImpl implements ValidationManager, Service,
 
 	private final DatabaseComponent db;
 	private final Executor dbExecutor, validationExecutor;
-	private final MessageFactory messageFactory;
 	private final Map<ClientMajorVersion, MessageValidator> validators;
 	private final Map<ClientMajorVersion, IncomingMessageHook> hooks;
 	private final AtomicBoolean used = new AtomicBoolean(false);
@@ -60,12 +58,10 @@ class ValidationManagerImpl implements ValidationManager, Service,
 	@Inject
 	ValidationManagerImpl(DatabaseComponent db,
 			@DatabaseExecutor Executor dbExecutor,
-			@ValidationExecutor Executor validationExecutor,
-			MessageFactory messageFactory) {
+			@ValidationExecutor Executor validationExecutor) {
 		this.db = db;
 		this.dbExecutor = dbExecutor;
 		this.validationExecutor = validationExecutor;
-		this.messageFactory = messageFactory;
 		validators = new ConcurrentHashMap<>();
 		hooks = new ConcurrentHashMap<>();
 	}
@@ -128,8 +124,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
 			Transaction txn = db.startTransaction(true);
 			try {
 				MessageId id = unvalidated.poll();
-				byte[] raw = db.getRawMessage(txn, id);
-				m = messageFactory.createMessage(id, raw);
+				m = db.getMessage(txn, id);
 				g = db.getGroup(txn, m.getGroupId());
 				db.commitTransaction(txn);
 			} finally {
@@ -196,8 +191,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
 						invalidateMessage(txn, id);
 						invalidate = getDependentsToInvalidate(txn, id);
 					} else if (allDelivered) {
-						byte[] raw = db.getRawMessage(txn, id);
-						Message m = messageFactory.createMessage(id, raw);
+						Message m = db.getMessage(txn, id);
 						Group g = db.getGroup(txn, m.getGroupId());
 						ClientId c = g.getClientId();
 						int majorVersion = g.getMajorVersion();
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/client/ClientHelperImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/client/ClientHelperImplTest.java
index abdce2893cc8ef4f69ca33f4f2535b20f5419f7a..9201e0c67b9f0febc9eceac989d6f9f7b384cf43 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/client/ClientHelperImplTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/client/ClientHelperImplTest.java
@@ -71,7 +71,6 @@ public class ClientHelperImplTest extends BrambleTestCase {
 	private final Message message = getMessage(groupId);
 	private final MessageId messageId = message.getId();
 	private final long timestamp = message.getTimestamp();
-	private final byte[] rawMessage = message.getRaw();
 	private final Metadata metadata = new Metadata();
 	private final BdfList list = BdfList.of("Sign this!", getRandomBytes(42));
 	private final String label = StringUtils.getRandomString(5);
@@ -120,8 +119,8 @@ public class ClientHelperImplTest extends BrambleTestCase {
 		context.checking(new Expectations() {{
 			oneOf(db).startTransaction(true);
 			will(returnValue(txn));
-			oneOf(db).getRawMessage(txn, messageId);
-			will(returnValue(rawMessage));
+			oneOf(db).getMessage(txn, messageId);
+			will(returnValue(message));
 			oneOf(db).commitTransaction(txn);
 			oneOf(db).endTransaction(txn);
 		}});
@@ -267,7 +266,7 @@ public class ClientHelperImplTest extends BrambleTestCase {
 	public void testToList() throws Exception {
 		expectToList(true);
 
-		assertEquals(list, clientHelper.toList(rawMessage));
+		assertEquals(list, clientHelper.toList(getRandomBytes(123)));
 		context.assertIsSatisfied();
 	}
 
@@ -276,7 +275,7 @@ public class ClientHelperImplTest extends BrambleTestCase {
 		expectToList(false); // no EOF after list
 
 		try {
-			clientHelper.toList(rawMessage);
+			clientHelper.toList(getRandomBytes(123));
 			fail();
 		} catch (FormatException e) {
 			// expected
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java
index 743e9632132e8db598dcdecf9defa90920067485..ee2a1a91c7a40a63f4e83283eed6c98b0db68e67 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java
@@ -613,11 +613,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
 			throws Exception {
 		context.checking(new Expectations() {{
 			// Check whether the message is in the DB (which it's not)
-			exactly(12).of(database).startTransaction();
+			exactly(11).of(database).startTransaction();
 			will(returnValue(txn));
-			exactly(12).of(database).containsMessage(txn, messageId);
+			exactly(11).of(database).containsMessage(txn, messageId);
 			will(returnValue(false));
-			exactly(12).of(database).abortTransaction(txn);
+			exactly(11).of(database).abortTransaction(txn);
 			// This is needed for getMessageStatus() to proceed
 			exactly(1).of(database).containsContact(txn, contactId);
 			will(returnValue(true));
@@ -655,16 +655,6 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
 			db.endTransaction(transaction);
 		}
 
-		transaction = db.startTransaction(false);
-		try {
-			db.getRawMessage(transaction, messageId);
-			fail();
-		} catch (NoSuchMessageException expected) {
-			// Expected
-		} finally {
-			db.endTransaction(transaction);
-		}
-
 		transaction = db.startTransaction(false);
 		try {
 			db.getMessageMetadata(transaction, messageId);
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/sync/ValidationManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/sync/ValidationManagerImplTest.java
index 3b4ae864a6bfc16d40a17067f6b8c33a13baf55a..5225f148d60924d33a6043f12740875846052d24 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/sync/ValidationManagerImplTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/sync/ValidationManagerImplTest.java
@@ -12,7 +12,6 @@ import org.briarproject.bramble.api.sync.GroupId;
 import org.briarproject.bramble.api.sync.InvalidMessageException;
 import org.briarproject.bramble.api.sync.Message;
 import org.briarproject.bramble.api.sync.MessageContext;
-import org.briarproject.bramble.api.sync.MessageFactory;
 import org.briarproject.bramble.api.sync.MessageId;
 import org.briarproject.bramble.api.sync.ValidationManager.IncomingMessageHook;
 import org.briarproject.bramble.api.sync.ValidationManager.MessageValidator;
@@ -45,8 +44,6 @@ import static org.briarproject.bramble.test.TestUtils.getRandomId;
 public class ValidationManagerImplTest extends BrambleMockTestCase {
 
 	private final DatabaseComponent db = context.mock(DatabaseComponent.class);
-	private final MessageFactory messageFactory =
-			context.mock(MessageFactory.class);
 	private final MessageValidator validator =
 			context.mock(MessageValidator.class);
 	private final IncomingMessageHook hook =
@@ -75,8 +72,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
 
 	@Before
 	public void setUp() {
-		vm = new ValidationManagerImpl(db, dbExecutor, validationExecutor,
-				messageFactory);
+		vm = new ValidationManagerImpl(db, dbExecutor, validationExecutor);
 		vm.registerMessageValidator(clientId, majorVersion, validator);
 		vm.registerIncomingMessageHook(clientId, majorVersion, hook);
 	}
@@ -136,9 +132,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
 			// Load the first raw message and group
 			oneOf(db).startTransaction(true);
 			will(returnValue(txn1));
-			oneOf(db).getRawMessage(txn1, messageId);
-			will(returnValue(message.getRaw()));
-			oneOf(messageFactory).createMessage(messageId, message.getRaw());
+			oneOf(db).getMessage(txn1, messageId);
 			will(returnValue(message));
 			oneOf(db).getGroup(txn1, groupId);
 			will(returnValue(group));
@@ -163,9 +157,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
 			// Load the second raw message and group
 			oneOf(db).startTransaction(true);
 			will(returnValue(txn3));
-			oneOf(db).getRawMessage(txn3, messageId1);
-			will(returnValue(message1.getRaw()));
-			oneOf(messageFactory).createMessage(messageId1, message1.getRaw());
+			oneOf(db).getMessage(txn3, messageId1);
 			will(returnValue(message1));
 			oneOf(db).getGroup(txn3, groupId);
 			will(returnValue(group));
@@ -237,9 +229,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
 			oneOf(db).getMessageDependencies(txn2, messageId);
 			will(returnValue(singletonMap(messageId1, DELIVERED)));
 			// Get the message and its metadata to deliver
-			oneOf(db).getRawMessage(txn2, messageId);
-			will(returnValue(message.getRaw()));
-			oneOf(messageFactory).createMessage(messageId, message.getRaw());
+			oneOf(db).getMessage(txn2, messageId);
 			will(returnValue(message));
 			oneOf(db).getGroup(txn2, groupId);
 			will(returnValue(group));
@@ -262,9 +252,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
 			oneOf(db).getMessageDependencies(txn3, messageId2);
 			will(returnValue(singletonMap(messageId1, DELIVERED)));
 			// Get the dependent and its metadata to deliver
-			oneOf(db).getRawMessage(txn3, messageId2);
-			will(returnValue(message2.getRaw()));
-			oneOf(messageFactory).createMessage(messageId2, message2.getRaw());
+			oneOf(db).getMessage(txn3, messageId2);
 			will(returnValue(message2));
 			oneOf(db).getGroup(txn3, groupId);
 			will(returnValue(group));
@@ -414,16 +402,14 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
 			// Load the first raw message - *gasp* it's gone!
 			oneOf(db).startTransaction(true);
 			will(returnValue(txn1));
-			oneOf(db).getRawMessage(txn1, messageId);
+			oneOf(db).getMessage(txn1, messageId);
 			will(throwException(new NoSuchMessageException()));
 			never(db).commitTransaction(txn1);
 			oneOf(db).endTransaction(txn1);
 			// Load the second raw message and group
 			oneOf(db).startTransaction(true);
 			will(returnValue(txn2));
-			oneOf(db).getRawMessage(txn2, messageId1);
-			will(returnValue(message1.getRaw()));
-			oneOf(messageFactory).createMessage(messageId1, message1.getRaw());
+			oneOf(db).getMessage(txn2, messageId1);
 			will(returnValue(message1));
 			oneOf(db).getGroup(txn2, groupId);
 			will(returnValue(group));
@@ -485,9 +471,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
 			// Load the first raw message
 			oneOf(db).startTransaction(true);
 			will(returnValue(txn1));
-			oneOf(db).getRawMessage(txn1, messageId);
-			will(returnValue(message.getRaw()));
-			oneOf(messageFactory).createMessage(messageId, message.getRaw());
+			oneOf(db).getMessage(txn1, messageId);
 			will(returnValue(message));
 			// Load the group - *gasp* it's gone!
 			oneOf(db).getGroup(txn1, groupId);
@@ -497,9 +481,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
 			// Load the second raw message and group
 			oneOf(db).startTransaction(true);
 			will(returnValue(txn2));
-			oneOf(db).getRawMessage(txn2, messageId1);
-			will(returnValue(message1.getRaw()));
-			oneOf(messageFactory).createMessage(messageId1, message1.getRaw());
+			oneOf(db).getMessage(txn2, messageId1);
 			will(returnValue(message1));
 			oneOf(db).getGroup(txn2, groupId);
 			will(returnValue(group));
@@ -860,9 +842,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
 			oneOf(db).getMessageDependencies(txn2, messageId1);
 			will(returnValue(singletonMap(messageId, DELIVERED)));
 			// Get message 1 and its metadata
-			oneOf(db).getRawMessage(txn2, messageId1);
-			will(returnValue(message1.getRaw()));
-			oneOf(messageFactory).createMessage(messageId1, message1.getRaw());
+			oneOf(db).getMessage(txn2, messageId1);
 			will(returnValue(message1));
 			oneOf(db).getGroup(txn2, groupId);
 			will(returnValue(group));
@@ -885,9 +865,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
 			oneOf(db).getMessageDependencies(txn3, messageId2);
 			will(returnValue(singletonMap(messageId, DELIVERED)));
 			// Get message 2 and its metadata
-			oneOf(db).getRawMessage(txn3, messageId2);
-			will(returnValue(message2.getRaw()));
-			oneOf(messageFactory).createMessage(messageId2, message2.getRaw());
+			oneOf(db).getMessage(txn3, messageId2);
 			will(returnValue(message2));
 			oneOf(db).getGroup(txn3, groupId);
 			will(returnValue(group));
@@ -910,9 +888,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
 			oneOf(db).getMessageDependencies(txn4, messageId3);
 			will(returnValue(twoDependencies));
 			// Get message 3 and its metadata
-			oneOf(db).getRawMessage(txn4, messageId3);
-			will(returnValue(message3.getRaw()));
-			oneOf(messageFactory).createMessage(messageId3, message3.getRaw());
+			oneOf(db).getMessage(txn4, messageId3);
 			will(returnValue(message3));
 			oneOf(db).getGroup(txn4, groupId);
 			will(returnValue(group));
@@ -941,9 +917,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
 			oneOf(db).getMessageDependencies(txn6, messageId4);
 			will(returnValue(singletonMap(messageId3, DELIVERED)));
 			// Get message 4 and its metadata
-			oneOf(db).getRawMessage(txn6, messageId4);
-			will(returnValue(message4.getRaw()));
-			oneOf(messageFactory).createMessage(messageId4, message4.getRaw());
+			oneOf(db).getMessage(txn6, messageId4);
 			will(returnValue(message4));
 			oneOf(db).getGroup(txn6, groupId);
 			will(returnValue(group));