diff --git a/app/controllers/api/v1/paypal.js b/app/controllers/api/v1/paypal.js index ebf343b720..c0b9f248de 100644 --- a/app/controllers/api/v1/paypal.js +++ b/app/controllers/api/v1/paypal.js @@ -10,6 +10,7 @@ const _ = require('lodash'); const isSANB = require('is-string-and-not-blank'); const ms = require('ms'); const parseErr = require('parse-err'); +const safeStringify = require('fast-safe-stringify'); const config = require('#config'); const emailHelper = require('#helpers/email'); @@ -416,7 +417,7 @@ async function processEvent(ctx) { subject: `Error while capturing PayPal order payment for ${user.email}` }, locals: { - message: `
${JSON.stringify(
+              message: `
${safeStringify(
                 parseErr(err),
                 null,
                 2
@@ -522,7 +523,7 @@ async function webhook(ctx) {
           subject: `Error with PayPal Webhook (Event ID ${ctx.request.body.id})`
         },
         locals: {
-          message: `
${JSON.stringify(
+          message: `
${safeStringify(
             parseErr(err),
             null,
             2
diff --git a/app/controllers/api/v1/stripe.js b/app/controllers/api/v1/stripe.js
index 274559fc10..1365eaa355 100644
--- a/app/controllers/api/v1/stripe.js
+++ b/app/controllers/api/v1/stripe.js
@@ -14,6 +14,7 @@ const ms = require('ms');
 const parseErr = require('parse-err');
 const pMapSeries = require('p-map-series');
 const titleize = require('titleize');
+const safeStringify = require('fast-safe-stringify');
 
 const { Users, Domains } = require('#models');
 const config = require('#config');
@@ -597,7 +598,7 @@ async function webhook(ctx) {
           subject: `Error with Stripe Webhook (Event ID ${event.id})`
         },
         locals: {
-          message: `
${JSON.stringify(
+          message: `
${safeStringify(
             parseErr(err),
             null,
             2
diff --git a/app/controllers/web/my-account/retrieve-domain-billing.js b/app/controllers/web/my-account/retrieve-domain-billing.js
index afe662e55d..a5683aee4e 100644
--- a/app/controllers/web/my-account/retrieve-domain-billing.js
+++ b/app/controllers/web/my-account/retrieve-domain-billing.js
@@ -16,6 +16,7 @@ const isSANB = require('is-string-and-not-blank');
 const ms = require('ms');
 const pMapSeries = require('p-map-series');
 const parseErr = require('parse-err');
+const safeStringify = require('fast-safe-stringify');
 const striptags = require('striptags');
 
 const config = require('#config');
@@ -674,7 +675,7 @@ async function retrieveDomainBilling(ctx) {
               : `Stripe Payment Intent/Method Error for ${ctx.state.user.email}`
           },
           locals: {
-            message: `
${JSON.stringify(
+            message: `
${safeStringify(
               parseErr(err),
               null,
               2
@@ -723,7 +724,7 @@ async function retrieveDomainBilling(ctx) {
                 } for ${ctx.state.user.email}`
               },
               locals: {
-                message: `
${JSON.stringify(
+                message: `
${safeStringify(
                   parseErr(err),
                   null,
                   2
@@ -810,7 +811,7 @@ async function retrieveDomainBilling(ctx) {
               subject: `Error retrieving/creating stripe payment for ${ctx.state.user.email}`
             },
             locals: {
-              message: `
${JSON.stringify(
+              message: `
${safeStringify(
                 parseErr(err),
                 null,
                 2
@@ -835,7 +836,7 @@ async function retrieveDomainBilling(ctx) {
             subject: `Error saving user for ${ctx.state.user.email}`
           },
           locals: {
-            message: `
${JSON.stringify(
+            message: `
${safeStringify(
               parseErr(err),
               null,
               2
@@ -906,7 +907,7 @@ async function retrieveDomainBilling(ctx) {
               } for ${ctx.state.user.email}`
             },
             locals: {
-              message: `
${JSON.stringify(
+              message: `
${safeStringify(
                 parseErr(err),
                 null,
                 2
@@ -1009,7 +1010,7 @@ async function retrieveDomainBilling(ctx) {
               subject: `Error while capturing PayPal order payment for ${ctx.state.user.email}`
             },
             locals: {
-              message: `
${JSON.stringify(
+              message: `
${safeStringify(
                 parseErr(err),
                 null,
                 2
@@ -1073,7 +1074,7 @@ async function retrieveDomainBilling(ctx) {
             subject: `Error retrieving/creating paypal payment for ${ctx.state.user.email}`
           },
           locals: {
-            message: `
${JSON.stringify(
+            message: `
${safeStringify(
               parseErr(err),
               null,
               2
@@ -1097,7 +1098,7 @@ async function retrieveDomainBilling(ctx) {
             subject: `Error saving user for ${ctx.state.user.email}`
           },
           locals: {
-            message: `
${JSON.stringify(
+            message: `
${safeStringify(
               parseErr(err),
               null,
               2
@@ -1154,7 +1155,7 @@ async function retrieveDomainBilling(ctx) {
               } for ${ctx.state.user.email}`
             },
             locals: {
-              message: `
${JSON.stringify(
+              message: `
${safeStringify(
                 parseErr(err),
                 null,
                 2
@@ -1302,7 +1303,7 @@ async function retrieveDomainBilling(ctx) {
               subject: `Error retrieving/creating paypal payment for ${ctx.state.user.email}`
             },
             locals: {
-              message: `
${JSON.stringify(
+              message: `
${safeStringify(
                 parseErr(err),
                 null,
                 2
@@ -1327,7 +1328,7 @@ async function retrieveDomainBilling(ctx) {
             subject: `Error saving user for ${ctx.state.user.email}`
           },
           locals: {
-            message: `
${JSON.stringify(
+            message: `
${safeStringify(
               parseErr(err),
               null,
               2
@@ -1392,7 +1393,7 @@ async function retrieveDomainBilling(ctx) {
               } for ${ctx.state.user.email}`
             },
             locals: {
-              message: `
${JSON.stringify(
+              message: `
${safeStringify(
                 parseErr(err),
                 null,
                 2
@@ -1483,7 +1484,7 @@ async function retrieveDomainBilling(ctx) {
                     } for ${ctx.state.user.email}`
                   },
                   locals: {
-                    message: `
${JSON.stringify(
+                    message: `
${safeStringify(
                       parseErr(err),
                       null,
                       2
@@ -1517,7 +1518,7 @@ async function retrieveDomainBilling(ctx) {
                     } for ${ctx.state.user.email}`
                   },
                   locals: {
-                    message: `
${JSON.stringify(
+                    message: `
${safeStringify(
                       parseErr(err),
                       null,
                       2
@@ -1604,7 +1605,7 @@ async function retrieveDomainBilling(ctx) {
             subject: `A refund error occurred for ${ctx.state.user.email}`
           },
           locals: {
-            message: `
${JSON.stringify(
+            message: `
${safeStringify(
               parseErr(err),
               null,
               2
@@ -1671,7 +1672,7 @@ async function retrieveDomainBilling(ctx) {
             subject: `A refund error occurred for ${ctx.state.user.email}`
           },
           locals: {
-            message: `
${JSON.stringify(
+            message: `
${safeStringify(
               parseErr(err),
               null,
               2
diff --git a/app/models/logs.js b/app/models/logs.js
index 0047f85049..e96a02ac0e 100644
--- a/app/models/logs.js
+++ b/app/models/logs.js
@@ -949,7 +949,7 @@ Logs.postCreate(async (doc, next) => {
         subject: `Code Bug: ${doc?.err?.name} - ${doc?.err?.message} (${doc.id})`
       },
       locals: {
-        message: `
${JSON.stringify(doc, null, 2)}
` + message: `
${safeStringify(doc, null, 2)}
` } }); next(); diff --git a/helpers/get-database.js b/helpers/get-database.js index 1a8f2c1eea..a660488089 100644 --- a/helpers/get-database.js +++ b/helpers/get-database.js @@ -14,6 +14,7 @@ const mongoose = require('mongoose'); const ms = require('ms'); const pRetry = require('p-retry'); const parseErr = require('parse-err'); +const safeStringify = require('fast-safe-stringify'); const { Builder } = require('json-sql'); const { boolean } = require('boolean'); @@ -1058,11 +1059,11 @@ function retryGetDatabase(...args) { locals: { message: `

${ error.dbFilePath - }


${JSON.stringify(
+              }


${safeStringify(
                 error.stats,
                 null,
                 2
-              )}
${JSON.stringify(
+              )}
${safeStringify(
                 parseErr(error),
                 null,
                 2
diff --git a/helpers/imap/on-append.js b/helpers/imap/on-append.js
index 0d126c701b..0c3f071d6f 100644
--- a/helpers/imap/on-append.js
+++ b/helpers/imap/on-append.js
@@ -258,7 +258,7 @@ async function onAppend(path, flags, date, raw, session, fn) {
                   },
                   locals: {
                     message: `${session.user.username} – ${err.message}`,
-                    // message: `
${JSON.stringify(
+                    // message: `
${safeStringify(
                     //   parseErr(err),
                     //   null,
                     //   2
diff --git a/helpers/logger.js b/helpers/logger.js
index 094dff6108..5c47cb81e8 100644
--- a/helpers/logger.js
+++ b/helpers/logger.js
@@ -283,12 +283,7 @@ for (const level of logger.config.levels) {
       // 
       // 
       try {
-        message = global.structuredClone(message, {
-          // avoid throwing
-          lossy: true,
-          // avoid throwing *and* looks for toJSON
-          json: true
-        });
+        message = global.structuredClone(message);
       } catch (err) {
         console.error({ message, err });
         message = JSON.parse(safeStringify(message));
@@ -300,12 +295,20 @@ for (const level of logger.config.levels) {
       // 
       // 
       try {
-        meta = global.structuredClone(meta, {
-          // avoid throwing
-          lossy: true,
-          // avoid throwing *and* looks for toJSON
-          json: true
-        });
+        //
+        // NOTE: we need to take into account that most instances of logger
+        // for IMAP/POP3 have `logger.fatal(err, { session })`
+        // and this causes unnecessary cloning of `session.getQueryResponse`
+        // and would cause `DOMException [DataCloneError]` from `structuredClone`
+        // and the alternative would be `logger.fatal(err, { session: _.omit(session, 'getQueryResponse') })`
+        // which is a lot to type everywhere and to remember so this is a safeguard
+        //
+        if (
+          typeof meta.session === 'object' &&
+          typeof meta.session.getQueryResponse === 'function'
+        )
+          meta.session = _.omit(meta.session, ['getQueryResponse']);
+        meta = global.structuredClone(meta);
       } catch (err) {
         console.error({ meta, err });
         message = JSON.parse(safeStringify(message));
diff --git a/helpers/on-auth.js b/helpers/on-auth.js
index a0f0378be6..6396a4dce9 100644
--- a/helpers/on-auth.js
+++ b/helpers/on-auth.js
@@ -76,8 +76,10 @@ async function onAuth(auth, session, fn) {
       }
     }
 
+    // NOTE: this is only required for WildDuck servers (IMAP/POP3)
     // override session.getQueryResponse (safeguard)
-    session.getQueryResponse = getQueryResponse;
+    if (this.server instanceof IMAPServer || this.server instanceof POP3Server)
+      session.getQueryResponse = getQueryResponse;
 
     // username must be a valid email address
     if (
diff --git a/helpers/process-email.js b/helpers/process-email.js
index 6e80aac23d..6ae7917de5 100644
--- a/helpers/process-email.js
+++ b/helpers/process-email.js
@@ -20,6 +20,7 @@ const pMap = require('p-map');
 const pMapSeries = require('p-map-series');
 const parseErr = require('parse-err');
 const prettyMilliseconds = require('pretty-ms');
+const safeStringify = require('fast-safe-stringify');
 const { SRS } = require('sender-rewriting-scheme');
 const { Splitter, Joiner } = require('mailsplit');
 const { authenticate } = require('mailauth');
@@ -1236,7 +1237,7 @@ async function processEmail({ email, port = 25, resolver, client }) {
                   domain.name,
                   domain.bounce_webhook
                 ) +
-                `
${JSON.stringify(
+                `
${safeStringify(
                   _.omit(parseErr(err), 'stack'),
                   null,
                   2
diff --git a/helpers/sync-paypal-subscription-payments-by-user.js b/helpers/sync-paypal-subscription-payments-by-user.js
index 115d8d0476..6515fb8c78 100644
--- a/helpers/sync-paypal-subscription-payments-by-user.js
+++ b/helpers/sync-paypal-subscription-payments-by-user.js
@@ -8,6 +8,7 @@ const isSANB = require('is-string-and-not-blank');
 const ms = require('ms');
 const pMapSeries = require('p-map-series');
 const parseErr = require('parse-err');
+const safeStringify = require('fast-safe-stringify');
 
 const emailHelper = require('./email');
 const logger = require('./logger');
@@ -244,7 +245,7 @@ async function syncPayPalSubscriptionPaymentsByUser(errorEmails, customer) {
                 subject: `${customer.email} had an issue syncing a transaction from paypal subscription ${subscriptionId} and transaction ${transaction.id}`
               },
               locals: {
-                message: `
${JSON.stringify(
+                message: `
${safeStringify(
                   parseErr(err),
                   null,
                   2
@@ -303,7 +304,7 @@ async function syncPayPalSubscriptionPaymentsByUser(errorEmails, customer) {
               subject: `${customer.email} has an issue syncing all payments from paypal subscription ${subscriptionId} that were not synced by the sync-payment-histories job`
             },
             locals: {
-              message: `
${JSON.stringify(
+              message: `
${safeStringify(
                 parseErr(err),
                 null,
                 2
@@ -330,7 +331,7 @@ async function syncPayPalSubscriptionPaymentsByUser(errorEmails, customer) {
             subject: `Sync PayPal payment histories hit ${config.paypalErrorThreshold} errors during the script`
           },
           locals: {
-            message: `
${JSON.stringify(
+            message: `
${safeStringify(
               parseErr(err),
               null,
               2
diff --git a/helpers/sync-stripe-payment-intent.js b/helpers/sync-stripe-payment-intent.js
index b22163bf8f..1f15171bf1 100644
--- a/helpers/sync-stripe-payment-intent.js
+++ b/helpers/sync-stripe-payment-intent.js
@@ -10,6 +10,7 @@ const dedent = require('dedent');
 const isSANB = require('is-string-and-not-blank');
 const ms = require('ms');
 const parseErr = require('parse-err');
+const safeStringify = require('fast-safe-stringify');
 
 const logger = require('./logger');
 const ThresholdError = require('./threshold-error');
@@ -439,7 +440,7 @@ function syncStripePaymentIntent(user) {
           subject: `Problem syncing billing history for ${user.email} - payment_intent ${paymentIntent.id}`
         },
         locals: {
-          message: `
${JSON.stringify(
+          message: `
${safeStringify(
             parseErr(err),
             null,
             2
diff --git a/jobs/bounce-report.js b/jobs/bounce-report.js
index 227b9f7eb3..02211fb32e 100644
--- a/jobs/bounce-report.js
+++ b/jobs/bounce-report.js
@@ -18,6 +18,7 @@ const Graceful = require('@ladjs/graceful');
 const dayjs = require('dayjs-with-plugins');
 const mongoose = require('mongoose');
 const parseErr = require('parse-err');
+const safeStringify = require('fast-safe-stringify');
 
 const config = require('#config');
 const emailHelper = require('#helpers/email');
@@ -88,7 +89,7 @@ graceful.listen();
         subject: 'Email Deliverability Report Issue'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2
diff --git a/jobs/check-pm2.js b/jobs/check-pm2.js
index 5bf178e59e..db4405dae0 100644
--- a/jobs/check-pm2.js
+++ b/jobs/check-pm2.js
@@ -20,6 +20,7 @@ const parseErr = require('parse-err');
 const pm2 = require('pm2');
 const prettyMilliseconds = require('pretty-ms');
 const ms = require('ms');
+const safeStringify = require('fast-safe-stringify');
 
 const config = require('#config');
 const emailHelper = require('#helpers/email');
@@ -151,7 +152,7 @@ graceful.listen();
         subject: 'Check PM2 had an error'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2
diff --git a/jobs/cleanup-sqlite.js b/jobs/cleanup-sqlite.js
index 1fb6c4fc93..4c622f96f7 100644
--- a/jobs/cleanup-sqlite.js
+++ b/jobs/cleanup-sqlite.js
@@ -25,6 +25,7 @@ const ms = require('ms');
 const pMapSeries = require('p-map-series');
 const parseErr = require('parse-err');
 const sharedConfig = require('@ladjs/shared-config');
+const safeStringify = require('fast-safe-stringify');
 
 const Aliases = require('#models/aliases');
 const Domains = require('#models/domains');
@@ -343,7 +344,7 @@ const mountDir = config.env === 'production' ? '/mnt' : tmpdir;
         subject: 'SQLite cleanup had an error'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2
diff --git a/jobs/cleanup-tmp.js b/jobs/cleanup-tmp.js
index f97243c102..8097c4cd5a 100644
--- a/jobs/cleanup-tmp.js
+++ b/jobs/cleanup-tmp.js
@@ -21,6 +21,7 @@ const ip = require('ip');
 const mongoose = require('mongoose');
 const ms = require('ms');
 const parseErr = require('parse-err');
+const safeStringify = require('fast-safe-stringify');
 const { getDirSize } = require('fast-dir-size');
 
 const config = require('#config');
@@ -121,7 +122,7 @@ graceful.listen();
         subject: 'Cleanup tmp had an error'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2
diff --git a/jobs/crawl-sitemap.js b/jobs/crawl-sitemap.js
index 3dd862392f..d91b3634a1 100644
--- a/jobs/crawl-sitemap.js
+++ b/jobs/crawl-sitemap.js
@@ -20,6 +20,7 @@ const isSANB = require('is-string-and-not-blank');
 const mongoose = require('mongoose');
 const ms = require('ms');
 const parseErr = require('parse-err');
+const safeStringify = require('fast-safe-stringify');
 const sharedConfig = require('@ladjs/shared-config');
 const splitLines = require('split-lines');
 const { XMLParser } = require('fast-xml-parser');
@@ -348,7 +349,7 @@ graceful.listen();
         subject: 'Crawl Sitemap Error'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2
diff --git a/jobs/delete-emails.js b/jobs/delete-emails.js
index fd92d14619..3f0cceba7b 100644
--- a/jobs/delete-emails.js
+++ b/jobs/delete-emails.js
@@ -15,6 +15,7 @@ require('#config/mongoose');
 const Graceful = require('@ladjs/graceful');
 const ms = require('ms');
 const parseErr = require('parse-err');
+const safeStringify = require('fast-safe-stringify');
 
 const mongoose = require('mongoose');
 const emailHelper = require('#helpers/email');
@@ -134,7 +135,7 @@ graceful.listen();
         subject: 'Delete Emails Issue'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2
diff --git a/jobs/delete-logs.js b/jobs/delete-logs.js
index da6dea7e83..b3fed66385 100644
--- a/jobs/delete-logs.js
+++ b/jobs/delete-logs.js
@@ -15,6 +15,7 @@ require('#config/mongoose');
 const Graceful = require('@ladjs/graceful');
 const ms = require('ms');
 const parseErr = require('parse-err');
+const safeStringify = require('fast-safe-stringify');
 
 const mongoose = require('mongoose');
 const emailHelper = require('#helpers/email');
@@ -65,7 +66,7 @@ graceful.listen();
         subject: 'Delete Logs Issue'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2
diff --git a/jobs/parse-logs.js b/jobs/parse-logs.js
index 2b833d2774..78ddcf3e3a 100644
--- a/jobs/parse-logs.js
+++ b/jobs/parse-logs.js
@@ -15,6 +15,7 @@ require('#config/mongoose');
 const Graceful = require('@ladjs/graceful');
 const parseErr = require('parse-err');
 const mongoose = require('mongoose');
+const safeStringify = require('fast-safe-stringify');
 
 const config = require('#config');
 const Logs = require('#models/logs');
@@ -143,7 +144,7 @@ graceful.listen();
         subject: 'Parse Logs Issue'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2
diff --git a/jobs/paypal/dup-tx-id.js b/jobs/paypal/dup-tx-id.js
index 07b5ed1b40..0026b1abc5 100644
--- a/jobs/paypal/dup-tx-id.js
+++ b/jobs/paypal/dup-tx-id.js
@@ -13,6 +13,7 @@ require('#config/mongoose');
 const Graceful = require('@ladjs/graceful');
 const parseErr = require('parse-err');
 const pMap = require('p-map');
+const safeStringify = require('fast-safe-stringify');
 
 const mongoose = require('mongoose');
 const config = require('#config');
@@ -72,7 +73,7 @@ async function mapper(id) {
         subject: 'Duplicate PayPal Transactions Detected'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2
diff --git a/jobs/paypal/index.js b/jobs/paypal/index.js
index 0abc5ac172..d221f51197 100644
--- a/jobs/paypal/index.js
+++ b/jobs/paypal/index.js
@@ -11,6 +11,7 @@ require('#config/mongoose');
 
 const Graceful = require('@ladjs/graceful');
 const parseErr = require('parse-err');
+const safeStringify = require('fast-safe-stringify');
 
 const mongoose = require('mongoose');
 const syncPayPalOrderPayments = require('./sync-paypal-order-payments');
@@ -49,7 +50,7 @@ graceful.listen();
         subject: 'Error with job for PayPal syncing of order payments'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2
@@ -73,7 +74,7 @@ graceful.listen();
         subject: 'Error with job for PayPal syncing of subscription payments'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2
diff --git a/jobs/paypal/sync-paypal-order-payments.js b/jobs/paypal/sync-paypal-order-payments.js
index 67b1a5c0d1..deaa7b4eca 100644
--- a/jobs/paypal/sync-paypal-order-payments.js
+++ b/jobs/paypal/sync-paypal-order-payments.js
@@ -5,6 +5,7 @@
 
 const pMapSeries = require('p-map-series');
 const parseErr = require('parse-err');
+const safeStringify = require('fast-safe-stringify');
 
 const emailHelper = require('#helpers/email');
 const Payments = require('#models/payments');
@@ -44,7 +45,7 @@ async function syncPayPalOrderPayments() {
         subject: 'Sync PayPal Orders had an error'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2
diff --git a/jobs/send-emails.js b/jobs/send-emails.js
index f879376987..6fed216160 100644
--- a/jobs/send-emails.js
+++ b/jobs/send-emails.js
@@ -8,17 +8,18 @@ require('#config/env');
 
 const process = require('node:process');
 const { parentPort } = require('node:worker_threads');
+const { setTimeout } = require('node:timers/promises');
 
 // eslint-disable-next-line import/no-unassigned-import
 require('#config/mongoose');
 
-const { setTimeout } = require('node:timers/promises');
 const Graceful = require('@ladjs/graceful');
 const Redis = require('@ladjs/redis');
 const dayjs = require('dayjs-with-plugins');
 const ip = require('ip');
 const mongoose = require('mongoose');
 const parseErr = require('parse-err');
+const safeStringify = require('fast-safe-stringify');
 const sharedConfig = require('@ladjs/shared-config');
 const { default: PQueue } = require('p-queue');
 
@@ -259,7 +260,7 @@ async function sendEmails() {
           subject: 'Send emails had an error'
         },
         locals: {
-          message: `
${JSON.stringify(
+          message: `
${safeStringify(
             parseErr(err),
             null,
             2
diff --git a/jobs/stripe/index.js b/jobs/stripe/index.js
index 2614e2fcd8..c27013e751 100644
--- a/jobs/stripe/index.js
+++ b/jobs/stripe/index.js
@@ -16,6 +16,7 @@ const _ = require('lodash');
 const pMap = require('p-map');
 const parseErr = require('parse-err');
 const mongoose = require('mongoose');
+const safeStringify = require('fast-safe-stringify');
 
 const syncStripePayments = require('./sync-stripe-payments');
 const fraudCheck = require('./fraud-check');
@@ -56,7 +57,7 @@ graceful.listen();
         subject: 'Error with job for Stripe fraud check'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2
@@ -82,7 +83,7 @@ graceful.listen();
         subject: 'Error with job for Stripe checking subscription accuracy'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2
@@ -131,7 +132,7 @@ graceful.listen();
         subject: 'Error with job for Stripe syncing of deleted subscriptions'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2
@@ -179,7 +180,7 @@ graceful.listen();
           'Error with job for Stripe checking of duplicate payment intent IDs'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2
@@ -203,7 +204,7 @@ graceful.listen();
         subject: 'Error with job for Stripe syncing of payments'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2
diff --git a/jobs/stripe/sync-stripe-payments.js b/jobs/stripe/sync-stripe-payments.js
index e99c1e99d0..78e58321ac 100644
--- a/jobs/stripe/sync-stripe-payments.js
+++ b/jobs/stripe/sync-stripe-payments.js
@@ -12,6 +12,7 @@ const ms = require('ms');
 const pMap = require('p-map');
 const pReduce = require('p-reduce');
 const parseErr = require('parse-err');
+const safeStringify = require('fast-safe-stringify');
 
 const getAllStripePaymentIntents = require('./get-all-stripe-payment-intents');
 const env = require('#config/env');
@@ -72,7 +73,7 @@ async function syncStripePayments() {
           subject: `Problem syncing billing history for ${user.email} - could not retrieve customer payments`
         },
         locals: {
-          message: `
${JSON.stringify(
+          message: `
${safeStringify(
             parseErr(err),
             null,
             2
@@ -185,7 +186,7 @@ async function syncStripePayments() {
           subject: `${user.email} has stripe payments that were not synced by the sync-payment-histories job`
         },
         locals: {
-          message: `
${JSON.stringify(
+          message: `
${safeStringify(
             parseErr(err),
             null,
             2
diff --git a/jobs/ubuntu-sync-memberships.js b/jobs/ubuntu-sync-memberships.js
index 97db70a57c..f939a34304 100644
--- a/jobs/ubuntu-sync-memberships.js
+++ b/jobs/ubuntu-sync-memberships.js
@@ -18,6 +18,7 @@ const mongoose = require('mongoose');
 const parseErr = require('parse-err');
 const pMapSeries = require('p-map-series');
 const sharedConfig = require('@ladjs/shared-config');
+const safeStringify = require('fast-safe-stringify');
 
 const Users = require('#models/users');
 const config = require('#config');
@@ -91,7 +92,7 @@ const resolver = createTangerine(client, logger);
         subject: 'Ubuntu Sync Memberships Issue'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2
diff --git a/jobs/visa-trial-subscription-requirement.js b/jobs/visa-trial-subscription-requirement.js
index 1b20e08dee..6d5e59d924 100644
--- a/jobs/visa-trial-subscription-requirement.js
+++ b/jobs/visa-trial-subscription-requirement.js
@@ -22,6 +22,7 @@ const isSANB = require('is-string-and-not-blank');
 const ms = require('ms');
 const parseErr = require('parse-err');
 const mongoose = require('mongoose');
+const safeStringify = require('fast-safe-stringify');
 
 const config = require('#config');
 const emailHelper = require('#helpers/email');
@@ -146,7 +147,7 @@ async function mapper(user) {
             subject: 'VISA Trial Subscription Requirement Error'
           },
           locals: {
-            message: `
${JSON.stringify(
+            message: `
${safeStringify(
               parseErr(err),
               null,
               2
@@ -361,7 +362,7 @@ async function mapper(user) {
         subject: 'VISA Trial Subscription Requirement Error'
       },
       locals: {
-        message: `
${JSON.stringify(
+        message: `
${safeStringify(
           parseErr(err),
           null,
           2