Skip to content

Pausing and Resuming

A profile can be put under a maintenance/blackout window — the mailbox, relay, or M365 tenant itself being temporarily unavailable, not a fault in pg_relay_notifier.

Pausing

-- pause one profile for its default window (now() + 7 days)
SELECT pgrelay_notifier.pause('mailer');

-- pause one profile until a specific time
SELECT pgrelay_notifier.pause('mailer', now() + interval '2 hours');

-- pause EVERY profile at once (p_profile_name NULL)
SELECT pgrelay_notifier.pause(NULL, now() + interval '30 minutes');

pause(p_profile_name, p_pause_until)p_profile_name NULL means every profile, not just one. p_pause_until:

  • Omitted — defaults to now() + 7 days.
  • A timestamp already in the past — treated as "don't pause at all": the call ends the profile not paused (paused_until is set to NULL), even if it was paused a moment before. It never raises and never silently leaves a stale pause sitting there.

Resuming

-- resume immediately
SELECT pgrelay_notifier.resume('mailer');

-- or schedule exactly when sending resumes, instead of resuming right now
SELECT pgrelay_notifier.resume('mailer', now() + interval '1 hour');

-- resume EVERY profile at once
SELECT pgrelay_notifier.resume(NULL);

resume(p_profile_name, p_resume_at) — same NULL-means-every-profile rule. p_resume_at:

  • Omitted — resumes immediately (paused_until cleared to NULL).
  • Given — stored verbatim as the new paused_until. This is functionally the same column write as pause(p_pause_until := x); resume() is just the more intuitive name to reach for when the intent is "let sending resume starting at this time" rather than "start a fresh pause."

Where the check happens

At dispatch(), not compose(). A message can still be drafted during a pause — only the actual enqueue into pg_relay's queue is rejected:

SELECT pgrelay_notifier.send('mailer', ARRAY['[email protected]'], 'Hi', 'body');
-- ERROR: profile mailer is paused until 2026-08-29 10:00:00+10

Because the check sits at the one real chokepoint every send path goes through, send(), send_mail(), and the attachment-variant UTL_MAIL functions all inherit it automatically — nothing extra needed on their part.

This split matters in practice: a draft composed during a blackout can still be dispatched with an explicit p_run_at, or by relying on the profile's own delay_seconds default, timed to land once the window ends — pausing doesn't force anyone to wait around and retry by hand.

A different "pause" from pg_relay's own

Don't confuse this with pg_relay's own pgrelay.disable('channel_name') — that stops an entire pg_relay channel at the queue level, which several notifier profiles (or entirely unrelated SQL-event producers sharing that channel) might depend on. pause()/resume() here work on one profile (or every profile) at the pg_relay_notifier level and never touch the queue at all. Reach for pgrelay.disable() to stop a channel outright; reach for pause()/resume() when the reason is specific to one mail endpoint being temporarily unavailable.

What pausing does not do

A notification already dispatched (status pending, sitting in pg_relay's queue) is unaffected by a later pause() call — pg_relay_notifier doesn't reach into the queue to retroactively pull anything back out; that's pg_relay's own territory, not this extension's. As of pg_relay v1.2, pg_relay itself provides pgrelay.cancel(p_id bigint) for exactly that case — combined with delay_seconds, that gives a DBA a way to handle an already-queued notification too, if it's ever needed. See pg_relay's own documentation for how to use it.

Access

pause()/resume() are admin-only (grant_admin()) — pausing a profile, especially every profile at once, is an operational decision, not a sending privilege.