diff --git a/keyserver/src/push/crypto.js b/keyserver/src/push/crypto.js
--- a/keyserver/src/push/crypto.js
+++ b/keyserver/src/push/crypto.js
@@ -1,6 +1,5 @@
 // @flow
 
-import type { EncryptResult } from '@commapp/olm';
 import apn from '@parse/node-apn';
 import crypto from 'crypto';
 import invariant from 'invariant';
@@ -18,14 +17,15 @@
   AndroidNotificationRescind,
   NotificationTargetDevice,
   SenderDeviceID,
+  EncryptedNotifUtilsAPI,
 } from 'lib/types/notif-types.js';
 import { toBase64URL } from 'lib/utils/base64.js';
 
-import { encryptAndUpdateOlmSession } from '../updaters/olm-session-updater.js';
 import { encrypt, generateKey } from '../utils/aes-crypto-utils.js';
 import { getOlmUtility } from '../utils/olm-utils.js';
 
 async function encryptAPNsNotification(
+  encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
   cookieID: string,
   senderDeviceID: SenderDeviceID,
   notification: apn.Notification,
@@ -71,26 +71,19 @@
 
     let dbPersistCondition;
     if (notificationSizeValidator) {
-      dbPersistCondition = ({
-        serializedPayload,
-      }: {
-        +[string]: EncryptResult,
-      }) => {
+      dbPersistCondition = (serializedPayload: string) => {
         const notifCopy = _cloneDeep(encryptedNotification);
-        notifCopy.payload.encryptedPayload = serializedPayload.body;
+        notifCopy.payload.encryptedPayload = serializedPayload;
         return notificationSizeValidator(notifCopy);
       };
     }
     const {
-      encryptedMessages: { serializedPayload },
-      dbPersistConditionViolated,
+      encryptedData: serializedPayload,
+      sizeLimitViolated: dbPersistConditionViolated,
       encryptionOrder,
-    } = await encryptAndUpdateOlmSession(
+    } = await encryptedNotifUtilsAPI.encryptSerializedNotifPayload(
       cookieID,
-      'notifications',
-      {
-        serializedPayload: unencryptedSerializedPayload,
-      },
+      unencryptedSerializedPayload,
       dbPersistCondition,
     );
 
@@ -140,6 +133,7 @@
 }
 
 async function encryptAndroidNotificationPayload<T>(
+  encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
   cookieID: string,
   senderDeviceID: SenderDeviceID,
   unencryptedPayload: T,
@@ -166,29 +160,23 @@
 
     let dbPersistCondition;
     if (payloadSizeValidator) {
-      dbPersistCondition = ({
-        serializedPayload,
-      }: {
-        +[string]: EncryptResult,
-      }) =>
+      dbPersistCondition = (serializedPayload: string) =>
         payloadSizeValidator({
-          encryptedPayload: serializedPayload.body,
+          encryptedPayload: serializedPayload,
           ...senderDeviceID,
         });
     }
 
     const {
-      encryptedMessages: { serializedPayload },
-      dbPersistConditionViolated,
+      encryptedData: serializedPayload,
+      sizeLimitViolated: dbPersistConditionViolated,
       encryptionOrder,
-    } = await encryptAndUpdateOlmSession(
+    } = await encryptedNotifUtilsAPI.encryptSerializedNotifPayload(
       cookieID,
-      'notifications',
-      {
-        serializedPayload: unencryptedSerializedPayload,
-      },
+      unencryptedSerializedPayload,
       dbPersistCondition,
     );
+
     return {
       resultPayload: {
         encryptedPayload: serializedPayload.body,
@@ -213,6 +201,7 @@
 }
 
 async function encryptAndroidVisualNotification(
+  encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
   senderDeviceID: SenderDeviceID,
   cookieID: string,
   notification: AndroidVisualNotification,
@@ -249,6 +238,7 @@
   }
   const { resultPayload, payloadSizeExceeded, encryptionOrder } =
     await encryptAndroidNotificationPayload(
+      encryptedNotifUtilsAPI,
       cookieID,
       senderDeviceID,
       unencryptedPayload,
@@ -267,6 +257,7 @@
 }
 
 async function encryptAndroidSilentNotification(
+  encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
   cookieID: string,
   senderDeviceID: SenderDeviceID,
   notification: AndroidNotificationRescind | AndroidBadgeOnlyNotification,
@@ -276,6 +267,7 @@
   // never exceed any FCM limit
   const { ...unencryptedPayload } = notification.data;
   const { resultPayload } = await encryptAndroidNotificationPayload(
+    encryptedNotifUtilsAPI,
     cookieID,
     senderDeviceID,
     unencryptedPayload,
@@ -300,6 +292,7 @@
 }
 
 async function encryptBasicPayload<T>(
+  encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
   cookieID: string,
   senderDeviceID: SenderDeviceID,
   basicPayload: T,
@@ -318,12 +311,11 @@
   }
 
   try {
-    const {
-      encryptedMessages: { serializedPayload },
-      encryptionOrder,
-    } = await encryptAndUpdateOlmSession(cookieID, 'notifications', {
-      serializedPayload: unencryptedSerializedPayload,
-    });
+    const { encryptedData: serializedPayload, encryptionOrder } =
+      await encryptedNotifUtilsAPI.encryptSerializedNotifPayload(
+        cookieID,
+        unencryptedSerializedPayload,
+      );
 
     return {
       ...senderDeviceID,
@@ -340,6 +332,7 @@
 }
 
 async function encryptWebNotification(
+  encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
   cookieID: string,
   senderDeviceID: SenderDeviceID,
   notification: PlainTextWebNotification,
@@ -347,6 +340,7 @@
   const { id, ...payloadSansId } = notification;
   const { encryptionOrder, ...encryptionResult } =
     await encryptBasicPayload<PlainTextWebNotificationPayload>(
+      encryptedNotifUtilsAPI,
       cookieID,
       senderDeviceID,
       payloadSansId,
@@ -359,12 +353,14 @@
 }
 
 async function encryptWNSNotification(
+  encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
   cookieID: string,
   senderDeviceID: SenderDeviceID,
   notification: PlainTextWNSNotification,
 ): Promise<{ +notification: WNSNotification, +encryptionOrder?: number }> {
   const { encryptionOrder, ...encryptionResult } =
     await encryptBasicPayload<PlainTextWNSNotification>(
+      encryptedNotifUtilsAPI,
       cookieID,
       senderDeviceID,
       notification,
@@ -376,6 +372,7 @@
 }
 
 function prepareEncryptedAPNsNotifications(
+  encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
   senderDeviceID: SenderDeviceID,
   devices: $ReadOnlyArray<NotificationTargetDevice>,
   notification: apn.Notification,
@@ -394,6 +391,7 @@
   const notificationPromises = devices.map(
     async ({ cookieID, deviceToken, blobHolder }) => {
       const notif = await encryptAPNsNotification(
+        encryptedNotifUtilsAPI,
         cookieID,
         senderDeviceID,
         notification,
@@ -408,6 +406,7 @@
 }
 
 function prepareEncryptedIOSNotificationRescind(
+  encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
   senderDeviceID: SenderDeviceID,
   devices: $ReadOnlyArray<NotificationTargetDevice>,
   notification: apn.Notification,
@@ -422,6 +421,7 @@
   const notificationPromises = devices.map(
     async ({ deviceToken, cookieID }) => {
       const { notification: notif } = await encryptAPNsNotification(
+        encryptedNotifUtilsAPI,
         cookieID,
         senderDeviceID,
         notification,
@@ -434,6 +434,7 @@
 }
 
 function prepareEncryptedAndroidVisualNotifications(
+  encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
   senderDeviceID: SenderDeviceID,
   devices: $ReadOnlyArray<NotificationTargetDevice>,
   notification: AndroidVisualNotification,
@@ -452,6 +453,7 @@
   const notificationPromises = devices.map(
     async ({ deviceToken, cookieID, blobHolder }) => {
       const notif = await encryptAndroidVisualNotification(
+        encryptedNotifUtilsAPI,
         senderDeviceID,
         cookieID,
         notification,
@@ -465,6 +467,7 @@
 }
 
 function prepareEncryptedAndroidSilentNotifications(
+  encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
   senderDeviceID: SenderDeviceID,
   devices: $ReadOnlyArray<NotificationTargetDevice>,
   notification: AndroidNotificationRescind | AndroidBadgeOnlyNotification,
@@ -479,6 +482,7 @@
   const notificationPromises = devices.map(
     async ({ deviceToken, cookieID }) => {
       const notif = await encryptAndroidSilentNotification(
+        encryptedNotifUtilsAPI,
         cookieID,
         senderDeviceID,
         notification,
@@ -490,6 +494,7 @@
 }
 
 function prepareEncryptedWebNotifications(
+  encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
   senderDeviceID: SenderDeviceID,
   devices: $ReadOnlyArray<NotificationTargetDevice>,
   notification: PlainTextWebNotification,
@@ -503,6 +508,7 @@
   const notificationPromises = devices.map(
     async ({ deviceToken, cookieID }) => {
       const notif = await encryptWebNotification(
+        encryptedNotifUtilsAPI,
         cookieID,
         senderDeviceID,
         notification,
@@ -514,6 +520,7 @@
 }
 
 function prepareEncryptedWNSNotifications(
+  encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
   senderDeviceID: SenderDeviceID,
   devices: $ReadOnlyArray<NotificationTargetDevice>,
   notification: PlainTextWNSNotification,
@@ -527,6 +534,7 @@
   const notificationPromises = devices.map(
     async ({ deviceToken, cookieID }) => {
       const notif = await encryptWNSNotification(
+        encryptedNotifUtilsAPI,
         cookieID,
         senderDeviceID,
         notification,
diff --git a/keyserver/src/push/encrypted-notif-utils-api.js b/keyserver/src/push/encrypted-notif-utils-api.js
new file mode 100644
--- /dev/null
+++ b/keyserver/src/push/encrypted-notif-utils-api.js
@@ -0,0 +1,49 @@
+// @flow
+
+import type { EncryptResult } from '@commapp/olm';
+
+import type { EncryptedNotifUtilsAPI } from 'lib/types/notif-types.js';
+
+import { blobServiceUpload } from './utils.js';
+import { encryptAndUpdateOlmSession } from '../updaters/olm-session-updater.js';
+
+const encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI = {
+  encryptSerializedNotifPayload: async (
+    cryptoID: string,
+    unencryptedPayload: string,
+    encryptedPayloadSizeValidator?: (encryptedPayload: string) => boolean,
+  ) => {
+    let dbPersistCondition;
+    if (encryptedPayloadSizeValidator) {
+      dbPersistCondition = ({
+        serializedPayload,
+      }: {
+        +[string]: EncryptResult,
+      }) => encryptedPayloadSizeValidator(serializedPayload.body);
+    }
+
+    const {
+      encryptedMessages: { serializedPayload },
+      dbPersistConditionViolated,
+      encryptionOrder,
+    } = await encryptAndUpdateOlmSession(
+      cryptoID,
+      'notifications',
+      {
+        serializedPayload: unencryptedPayload,
+      },
+      dbPersistCondition,
+    );
+
+    return {
+      encryptedData: serializedPayload,
+      sizeLimitViolated: dbPersistConditionViolated,
+      encryptionOrder,
+    };
+  },
+  uploadLargeNotifPayload: blobServiceUpload,
+  getNotifByteSize: (serializedPayload: string) =>
+    Buffer.byteLength(serializedPayload),
+};
+
+export default encryptedNotifUtilsAPI;
diff --git a/keyserver/src/push/rescind.js b/keyserver/src/push/rescind.js
--- a/keyserver/src/push/rescind.js
+++ b/keyserver/src/push/rescind.js
@@ -10,6 +10,7 @@
   NotificationTargetDevice,
   TargetedAndroidNotification,
   SenderDeviceID,
+  EncryptedNotifUtilsAPI,
 } from 'lib/types/notif-types.js';
 import { threadSubscriptions } from 'lib/types/subscription-types.js';
 import { threadPermissions } from 'lib/types/thread-permission-types.js';
@@ -20,6 +21,7 @@
   prepareEncryptedAndroidSilentNotifications,
   prepareEncryptedIOSNotificationRescind,
 } from './crypto.js';
+import encryptedNotifUtilsAPI from './encrypted-notif-utils-api.js';
 import { getAPNsNotificationTopic } from './providers.js';
 import type { TargetedAPNsNotification } from './types.js';
 import {
@@ -275,11 +277,13 @@
 }
 
 async function conditionallyEncryptNotification<T>(
+  encryptedNotifUtilsAPIInstance: EncryptedNotifUtilsAPI,
   senderDeviceID: SenderDeviceID,
   notification: T,
   codeVersion: ?number,
   devices: $ReadOnlyArray<NotificationTargetDevice>,
   encryptCallback: (
+    encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
     senderDeviceID: SenderDeviceID,
     devices: $ReadOnlyArray<NotificationTargetDevice>,
     notification: T,
@@ -301,6 +305,7 @@
     }));
   }
   const notifications = await encryptCallback(
+    encryptedNotifUtilsAPI,
     senderDeviceID,
     devices,
     notification,
@@ -354,6 +359,7 @@
           },
         };
   return await conditionallyEncryptNotification(
+    encryptedNotifUtilsAPI,
     { keyserverID },
     notification,
     codeVersion,
@@ -383,6 +389,7 @@
     },
   };
   const targetedRescinds = await conditionallyEncryptNotification(
+    encryptedNotifUtilsAPI,
     { keyserverID },
     notification,
     codeVersion,
diff --git a/keyserver/src/push/send.js b/keyserver/src/push/send.js
--- a/keyserver/src/push/send.js
+++ b/keyserver/src/push/send.js
@@ -56,6 +56,7 @@
   prepareEncryptedWebNotifications,
   prepareEncryptedWNSNotifications,
 } from './crypto.js';
+import encryptedNotifUtilsAPI from './encrypted-notif-utils-api.js';
 import { getAPNsNotificationTopic } from './providers.js';
 import { rescindPushNotifs } from './rescind.js';
 import type { TargetedAPNsNotification } from './types.js';
@@ -70,7 +71,6 @@
   wnsMaxNotificationPayloadByteSize,
   wnsPush,
   type WNSPushError,
-  blobServiceUpload,
 } from './utils.js';
 import createIDs from '../creators/id-creator.js';
 import { createUpdates } from '../creators/update-creator.js';
@@ -1039,6 +1039,7 @@
   if (platformDetails.platform === 'macos') {
     const macOSNotifsWithoutMessageInfos =
       await prepareEncryptedAPNsNotifications(
+        encryptedNotifUtilsAPI,
         { keyserverID },
         devices,
         notification,
@@ -1053,6 +1054,7 @@
   }
 
   const notifsWithMessageInfos = await prepareEncryptedAPNsNotifications(
+    encryptedNotifUtilsAPI,
     { keyserverID },
     devices,
     copyWithMessageInfos,
@@ -1090,7 +1092,7 @@
   let blobHash, blobHolders, encryptionKey, blobUploadError;
   if (canQueryBlobService) {
     ({ blobHash, blobHolders, encryptionKey, blobUploadError } =
-      await blobServiceUpload(
+      await encryptedNotifUtilsAPI.uploadLargeNotifPayload(
         copyWithMessageInfos.compile(),
         devicesWithExcessiveSizeNoHolders.length,
       ));
@@ -1123,6 +1125,7 @@
   }
 
   const notifsWithoutMessageInfos = await prepareEncryptedAPNsNotifications(
+    encryptedNotifUtilsAPI,
     { keyserverID },
     devicesWithExcessiveSize,
     notification,
@@ -1247,8 +1250,9 @@
   const priority = 'high';
   if (!shouldBeEncrypted) {
     const notificationToSend =
-      Buffer.byteLength(JSON.stringify(copyWithMessageInfos)) <=
-      fcmMaxNotificationPayloadByteSize
+      encryptedNotifUtilsAPI.getNotifByteSize(
+        JSON.stringify(copyWithMessageInfos),
+      ) <= fcmMaxNotificationPayloadByteSize
         ? copyWithMessageInfos
         : notification;
 
@@ -1263,12 +1267,14 @@
     const serializedNotif = JSON.stringify(notif);
     return (
       !serializedNotif ||
-      Buffer.byteLength(serializedNotif) <= fcmMaxNotificationPayloadByteSize
+      encryptedNotifUtilsAPI.getNotifByteSize(serializedNotif) <=
+        fcmMaxNotificationPayloadByteSize
     );
   };
 
   const notifsWithMessageInfos =
     await prepareEncryptedAndroidVisualNotifications(
+      encryptedNotifUtilsAPI,
       { keyserverID },
       devices,
       copyWithMessageInfos,
@@ -1297,7 +1303,7 @@
   let blobHash, blobHolders, encryptionKey, blobUploadError;
   if (canQueryBlobService) {
     ({ blobHash, blobHolders, encryptionKey, blobUploadError } =
-      await blobServiceUpload(
+      await encryptedNotifUtilsAPI.uploadLargeNotifPayload(
         JSON.stringify(copyWithMessageInfos.data),
         devicesWithExcessiveSizeNoHolders.length,
       ));
@@ -1331,6 +1337,7 @@
 
   const notifsWithoutMessageInfos =
     await prepareEncryptedAndroidVisualNotifications(
+      encryptedNotifUtilsAPI,
       { keyserverID },
       devicesWithExcessiveSize,
       notification,
@@ -1402,6 +1409,7 @@
   }
 
   return prepareEncryptedWebNotifications(
+    encryptedNotifUtilsAPI,
     { keyserverID },
     devices,
     notification,
@@ -1440,7 +1448,7 @@
   };
 
   if (
-    Buffer.byteLength(JSON.stringify(notification)) >
+    encryptedNotifUtilsAPI.getNotifByteSize(JSON.stringify(notification)) >
     wnsMaxNotificationPayloadByteSize
   ) {
     console.warn('WNS notification exceeds size limit');
@@ -1457,6 +1465,7 @@
     }));
   }
   return await prepareEncryptedWNSNotifications(
+    encryptedNotifUtilsAPI,
     { keyserverID },
     devices,
     notification,
@@ -1813,6 +1822,7 @@
         let targetedNotifications: $ReadOnlyArray<TargetedAPNsNotification>;
         if (codeVersion > 222) {
           const notificationsArray = await prepareEncryptedAPNsNotifications(
+            encryptedNotifUtilsAPI,
             { keyserverID },
             deviceInfos,
             notification,
@@ -1865,6 +1875,7 @@
         if (codeVersion > 222) {
           const notificationsArray =
             await prepareEncryptedAndroidSilentNotifications(
+              encryptedNotifUtilsAPI,
               { keyserverID },
               deviceInfos,
               notification,
@@ -1923,6 +1934,7 @@
         let targetedNotifications: $ReadOnlyArray<TargetedAPNsNotification>;
         if (shouldBeEncrypted) {
           const notificationsArray = await prepareEncryptedAPNsNotifications(
+            encryptedNotifUtilsAPI,
             { keyserverID },
             deviceInfos,
             notification,
diff --git a/lib/types/notif-types.js b/lib/types/notif-types.js
--- a/lib/types/notif-types.js
+++ b/lib/types/notif-types.js
@@ -1,5 +1,5 @@
 // @flow
-
+import type { EncryptResult } from '@commapp/olm';
 import t, { type TInterface } from 'tcomb';
 
 import type { EntityText, ThreadEntity } from '../utils/entity-text.js';
@@ -198,3 +198,27 @@
   +deviceToken: string,
   +blobHolder?: string,
 };
+
+export type EncryptedNotifUtilsAPI = {
+  +encryptSerializedNotifPayload: (
+    cryptoID: string,
+    unencryptedPayload: string,
+    encryptedPayloadSizeValidator?: (encryptedPayload: string) => boolean,
+  ) => Promise<{
+    +encryptedData: EncryptResult,
+    +sizeLimitViolated?: boolean,
+    +encryptionOrder?: number,
+  }>,
+  +uploadLargeNotifPayload: (
+    payload: string,
+    numberOfHolders: number,
+  ) => Promise<
+    | {
+        +blobHolders: $ReadOnlyArray<string>,
+        +blobHash: string,
+        +encryptionKey: string,
+      }
+    | { +blobUploadError: string },
+  >,
+  +getNotifByteSize: (serializedNotification: string) => number,
+};