Skip to main content

supercode_harness/
mail_send.rs

1//! One send for every sender: `supercode message send`, the native agent's
2//! `send_message`, and a request arriving through another machine's mail
3//! door. It resolves the receiver, routes to another machine through Teams or
4//! to the router's door here, guards against loops and repeats, and words
5//! the outcome for the sending agent.
6
7use std::path::PathBuf;
8
9use crate::mail_route::{Caller, Door, LiveSessions, Unresolved};
10use crate::mailbox::{
11    local_machine_name, mail_root, Envelope, MailAddress, MailKind, Mailbox, ReplyVia,
12};
13use crate::HarnessHomes;
14
15/// Exit code of a refused send.
16pub const EXIT_REFUSED: i32 = 2;
17/// Exit code of an unknown or stale receiver.
18pub const EXIT_UNKNOWN: i32 = 3;
19/// Exit code of a message stored with no door to show it.
20pub const EXIT_STORED: i32 = 4;
21/// Exit code of a failed send.
22pub const EXIT_FAILED: i32 = 5;
23
24/// What a delivery came to: the exit code, and the text the sending agent reads.
25pub struct Outcome {
26    /// Exit code for scripts: 0 sent, [`EXIT_REFUSED`], [`EXIT_UNKNOWN`],
27    /// [`EXIT_STORED`] or [`EXIT_FAILED`].
28    pub code: i32,
29    /// What the sending agent reads.
30    pub text: String,
31    /// Native delivery evidence, or the retained terminal queue state.
32    pub receipt: Option<serde_json::Value>,
33}
34
35impl Outcome {
36    /// An outcome with this code and text.
37    pub fn new(code: i32, text: impl Into<String>) -> Self {
38        Self {
39            code,
40            text: text.into(),
41            receipt: None,
42        }
43    }
44}
45
46/// Options of one send.
47#[derive(Debug, Clone, Default)]
48pub struct SendOptions {
49    /// A short subject, separate from the unchanged message body.
50    pub subject: Option<String>,
51    /// Id of the message this one answers.
52    pub in_reply_to: Option<String>,
53    /// Also send one notice when the receiver's next turn ends.
54    pub notify_when_idle: bool,
55    /// Only enqueue; never start a turn in an idle receiver.
56    pub queue: bool,
57    /// Idempotency key: repeating a send with it does not send twice.
58    pub idempotency_key: Option<String>,
59    /// An automated notice (a Teams transition), not a person's or a session's message:
60    /// filed as `notice`, with nothing to answer.
61    pub notice: bool,
62}
63
64/// Send `body` from `caller` to `to` (an address, `name@machine`, or a name
65/// unique on this machine): through Teams when `to` is on another machine,
66/// else through the router's door here. The one send every sender uses.
67pub async fn send(
68    homes: &HarnessHomes,
69    caller: &Caller,
70    to: &str,
71    body: &str,
72    options: SendOptions,
73) -> std::io::Result<Outcome> {
74    let SendOptions {
75        subject,
76        in_reply_to,
77        notify_when_idle,
78        queue,
79        idempotency_key,
80        notice,
81    } = options;
82    if let Some(machine) = remote_machine(to) {
83        let request = serde_json::json!({
84            "op": "send",
85            "from": caller.address.to_string(),
86            "from_name": caller.name,
87            "to": to,
88            "body": body,
89            "subject": subject,
90            "in_reply_to": in_reply_to,
91            "notify_when_idle": notify_when_idle,
92            "queue": queue,
93            "id": idempotency_key,
94            "notice": notice,
95        });
96        return Ok(remote_send(&machine, &request));
97    }
98    deliver(
99        homes,
100        caller,
101        to,
102        body,
103        subject,
104        in_reply_to,
105        notify_when_idle,
106        queue,
107        idempotency_key,
108        notice,
109    )
110    .await
111}
112
113/// The machine `to` names when it is not this one.
114fn remote_machine(to: &str) -> Option<String> {
115    let local = local_machine_name();
116    let machine = match MailAddress::parse(to) {
117        Ok(address) => address.machine,
118        Err(_) => to.rsplit_once('@')?.1.to_string(),
119    };
120    (machine != local).then_some(machine)
121}
122
123/// Hand a request to another machine's mail door through Teams.
124fn remote_send(machine: &str, request: &serde_json::Value) -> Outcome {
125    match crate::mailbox::teams_mail(machine, request) {
126        Ok(answer) => {
127            let mut outcome = Outcome::new(
128                answer["code"]
129                    .as_i64()
130                    .map_or(EXIT_FAILED, |code| code as i32),
131                answer["text"]
132                    .as_str()
133                    .or_else(|| answer["detail"].as_str())
134                    .unwrap_or("the other machine answered nothing readable")
135                    .to_string(),
136            );
137            outcome.receipt = answer.get("receipt").cloned();
138            outcome
139        }
140        Err(detail) if detail.contains("no mail grant") => Outcome::new(
141            EXIT_REFUSED,
142            format!(
143                "Not sent: machine {machine} does not accept mail from you (no mail grant). Only \
144                 an operator can grant it; tell your user. Don't retry."
145            ),
146        ),
147        Err(detail) => Outcome::new(
148            EXIT_FAILED,
149            format!("Not sent to machine {machine}: {detail}"),
150        ),
151    }
152}
153
154/// Deliver from `caller` to `to` on this machine, through the one router
155/// every sender uses (`crate::mail_route`).
156#[allow(clippy::too_many_arguments)]
157async fn deliver(
158    homes: &HarnessHomes,
159    caller: &Caller,
160    to: &str,
161    body: &str,
162    subject: Option<String>,
163    in_reply_to: Option<String>,
164    notify_when_idle: bool,
165    queue: bool,
166    idempotency_key: Option<String>,
167    notice: bool,
168) -> std::io::Result<Outcome> {
169    use crate::mail_route::{deliver as route, door_for, Delivered, Refused};
170    // An operator (a board, a script) is not a listed session; its address is
171    // taken as given.
172    // `operator:<name>` is that operator on this machine: a tool files what it posts on the
173    // session's behalf without knowing the machine's name.
174    let local_operator = to
175        .strip_prefix("operator:")
176        .and_then(|name| MailAddress::new(local_machine_name(), "operator", name).ok());
177    let (address, name) = match local_operator
178        .map(Ok)
179        .unwrap_or_else(|| MailAddress::parse(to))
180    {
181        // a board is an operator too: its dispatcher reads its mailbox (answers to the questions it asks)
182        Ok(address) if address.harness == "operator" || address.harness == "board" => {
183            let name = format!("{}@{}", address.session_id, address.machine);
184            (address, name)
185        }
186        // an agent's one mailbox: the mailbox decides which of its sessions receives it
187        Ok(address) if address.harness == crate::mail_agent::AGENT_HARNESS => {
188            if crate::mail_agent::load(&address.session_id).is_none() {
189                return Ok(Outcome::new(
190                    EXIT_UNKNOWN,
191                    format!(
192                        "No agent named {} is declared on this machine. Nothing was sent. Run \
193                         supercode agent show for the declared agents.",
194                        address.session_id
195                    ),
196                ));
197            }
198            let name = format!("agent {}@{}", address.session_id, address.machine);
199            (address, name)
200        }
201        _ => match LiveSessions::read(homes).resolve(to) {
202            Ok(session) => (session.address.clone(), session.name.clone()),
203            Err(Unresolved::Stale(message) | Unresolved::Unknown(message)) => {
204                return Ok(Outcome::new(EXIT_UNKNOWN, message));
205            }
206        },
207    };
208    if address == caller.address {
209        return Ok(Outcome::new(
210            EXIT_REFUSED,
211            "Not sent: that address is your own session.",
212        ));
213    }
214    // A message an agent's mailbox routes (a thread's reply, a root to an agent) may reach a
215    // session that has stopped: it is resumed. Anything else needs its receiver running.
216    let door = door_for(homes, &address).ok();
217    let message_id = crate::mail_file::message_id_for(&caller.address, idempotency_key.as_deref())?;
218    let sent_marker = sent_marker(&caller.address, &message_id);
219    let terminal = matches!(&door, Some(Door::Hook { pane: Some(_), .. }));
220    if let Ok(previous) = std::fs::read_to_string(&sent_marker) {
221        if terminal && !queue {
222            Mailbox::open(&mail_root(), &address)?.request_wake(&message_id)?;
223        }
224        let mut outcome = Outcome::new(
225            0,
226            format!(
227                "Already sent with --id {}: {previous} Nothing was sent again.",
228                idempotency_key.as_deref().unwrap_or_default()
229            ),
230        );
231        outcome.receipt = Some(delivery_receipt(&address, &message_id, terminal));
232        return Ok(outcome);
233    }
234    // An answered message is named as the agent was shown it, by a prefix of its id: the one in
235    // the caller's mailbox it names.
236    // A prefix names the one message it matches there, or nothing is sent; a whole id is kept as
237    // given (it may answer a message filed elsewhere).
238    let in_reply_to = match in_reply_to {
239        Some(answered) if answered.len() < FULL_ID_LEN => {
240            let found = Mailbox::open(&mail_root(), &caller.address)
241                .and_then(|mailbox| mailbox.find_prefix(&answered))
242                .unwrap_or_default();
243            match found.as_slice() {
244                [only] => Some(only.envelope.id.clone()),
245                [] => {
246                    return Ok(Outcome::new(
247                        EXIT_REFUSED,
248                        format!(
249                            "Not sent: no message in your mailbox has an id starting {answered}. \
250                             Name the message you answer as its envelope shows it."
251                        ),
252                    ))
253                }
254                many => {
255                    let ids: Vec<&str> = many
256                        .iter()
257                        .map(|stored| stored.envelope.id.as_str())
258                        .collect();
259                    return Ok(Outcome::new(
260                        EXIT_REFUSED,
261                        format!(
262                            "Not sent: {answered} names {} messages in your mailbox ({}). Give \
263                             more of its id.",
264                            ids.len(),
265                            ids.join(", ")
266                        ),
267                    ));
268                }
269            }
270        }
271        other => other,
272    };
273    if let Some(answered) = in_reply_to.as_deref().filter(|id| id.starts_with("q-")) {
274        return crate::mail_question::reply(caller, &address, answered, body).await;
275    }
276    if let Some(answered) = in_reply_to.as_deref() {
277        if reply_chain_depth(&caller.address, &address, answered) >= REPLY_CHAIN_LIMIT {
278            return Ok(Outcome::new(
279                EXIT_REFUSED,
280                format!(
281                    "Not sent: you and {name} have answered each other {REPLY_CHAIN_LIMIT} times \
282                     in a row. If you are trading acknowledgements or status, stop; to go on, \
283                     send a new message (without --re), or tell your user."
284                ),
285            ));
286        }
287    }
288    let (kind, reply_via) = if notice {
289        (MailKind::Notice, ReplyVia::None)
290    } else {
291        (MailKind::Peer, ReplyVia::Command)
292    };
293    let mut envelope = Envelope::new(
294        caller.address.clone(),
295        caller.name.clone(),
296        kind,
297        reply_via,
298        body,
299    )?;
300    envelope.subject = subject.as_deref().map(|value| {
301        value
302            .lines()
303            .next()
304            .unwrap_or("")
305            .chars()
306            .take(200)
307            .collect()
308    });
309    envelope.id = message_id.clone();
310    envelope.thread = crate::mailbox::thread_of_reply(in_reply_to.as_deref());
311    envelope.in_reply_to = in_reply_to;
312    if let Some(plan) = crate::mail_agent::plan(
313        &mut envelope,
314        &address,
315        &crate::mail_agent::Channel::default(),
316    )? {
317        return Ok(deliver_planned(homes, caller, &envelope, &plan, queue, notify_when_idle).await);
318    }
319    let Some(door) = door else {
320        return Ok(Outcome::new(
321            EXIT_UNKNOWN,
322            format!(
323                "{name} is no longer running. Nothing was sent. Run supercode message list for \
324                 the live sessions."
325            ),
326        ));
327    };
328    let tier = door.name();
329    let idle_note = if notify_when_idle {
330        " Subscribed: one idle notice reaches you when its next turn ends."
331    } else {
332        ""
333    };
334    let (code, what) = match route(&envelope, &address, &door, !queue, notify_when_idle).await {
335        Err(detail) => {
336            return Ok(Outcome::new(
337                EXIT_FAILED,
338                format!("Not sent to {name}: {detail}"),
339            ))
340        }
341        Ok(Err(Refused::CannotQueueNative)) => {
342            return Ok(Outcome::new(
343                EXIT_REFUSED,
344                format!(
345                    "Not sent: {name} is idle, and a Claude session always starts a turn when a \
346                     message arrives, so --queue cannot hold it. Send without --queue to wake it."
347                ),
348            ))
349        }
350        Ok(Err(Refused::TooLong(bytes))) => {
351            return Ok(Outcome::new(
352                EXIT_REFUSED,
353                format!(
354                    "Not sent: the message is {bytes} bytes; the limit is {}. Write it to a file \
355                     and send its path instead.",
356                    crate::mail_route::MAX_RELAYED_BYTES
357                ),
358            ))
359        }
360        Ok(Ok(Delivered::Steered)) => (0, "steered into its running turn"),
361        Ok(Ok(Delivered::Started)) => (0, "it was idle, so the message started a turn"),
362        Ok(Ok(Delivered::Native { busy: true })) => (0, "it will read it at its next tool call"),
363        Ok(Ok(Delivered::Native { busy: false })) => {
364            (0, "it was idle, so the message starts its next turn")
365        }
366        Ok(Ok(Delivered::Hooked)) => (
367            0,
368            "queued in its mailbox; terminal delivery waits for native transcript confirmation",
369        ),
370        Ok(Ok(Delivered::HookWoken)) => (
371            0,
372            "it was idle, so its pane was told to read its mailbox; its hook shows it the message in \
373             that turn",
374        ),
375        Ok(Ok(Delivered::Queued)) => (
376            0,
377            "it is idle and --queue leaves it so; the message waits in its mailbox",
378        ),
379        Ok(Ok(Delivered::Operator)) => (0, "filed in its mailbox"),
380        Ok(Ok(Delivered::Already)) => (0, "it already had this message; nothing was sent again"),
381        Ok(Ok(Delivered::Stored)) => (
382            EXIT_STORED,
383            "Stored (not failed): it has no delivery door, so it sees this only if it runs \
384             supercode message inbox (a Codex session gets one with: supercode message setup \
385             codex). Don't resend, and don't wait for a reply",
386        ),
387    };
388    record_send(&caller.address, &address, &message_id);
389    let shown_id = crate::mailbox::short_id(&message_id);
390    let text = if code == 0 {
391        format!(
392            "sent to {name} ({}, {tier}): {what}. Message id {shown_id}.{idle_note} Don't poll; \
393             carry on.",
394            address.harness
395        )
396    } else {
397        format!(
398            "{name} ({}): {what}. Message id {shown_id}.{idle_note}",
399            address.harness
400        )
401    };
402    if code == 0 && idempotency_key.is_some() {
403        if let Some(parent) = sent_marker.parent() {
404            std::fs::create_dir_all(parent).ok();
405        }
406        std::fs::write(&sent_marker, &text).ok();
407    }
408    let mut outcome = Outcome::new(code, text);
409    if code == 0 {
410        outcome.receipt = Some(delivery_receipt(&address, &message_id, terminal));
411    }
412    Ok(outcome)
413}
414
415/// Deliver `envelope` to every receiver `plan` names: a `to` receiver through its door (a
416/// stopped session is resumed first), a `cc` receiver filed unread and not woken. The one
417/// delivery every agent-routed message takes, whichever door it came in by.
418pub async fn deliver_planned(
419    homes: &HarnessHomes,
420    caller: &Caller,
421    envelope: &Envelope,
422    plan: &crate::mail_agent::Plan,
423    queue: bool,
424    notify_when_idle: bool,
425) -> Outcome {
426    let mut reached: Vec<String> = Vec::new();
427    let mut copied: Vec<String> = Vec::new();
428    let mut failed: Vec<String> = Vec::new();
429    if let Some(agent) = &plan.agent {
430        // The agent's own mailbox keeps the record of what was addressed to it.
431        if let Err(error) =
432            Mailbox::open(&mail_root(), agent).and_then(|mailbox| mailbox.deliver_read(envelope))
433        {
434            failed.push(format!("the agent's mailbox ({error})"));
435        }
436    }
437    for recipient in plan
438        .recipients
439        .iter()
440        .filter(|recipient| recipient.address != caller.address)
441    {
442        let label = recipient_label(homes, &recipient.address);
443        record_send(&caller.address, &recipient.address, &envelope.id);
444        if !recipient.wake {
445            match crate::mail_agent::file_unread(&recipient.address, envelope) {
446                Ok(()) => copied.push(label),
447                Err(error) => failed.push(format!("{label} ({error})")),
448            }
449            continue;
450        }
451        match deliver_woken(homes, envelope, &recipient.address, queue, notify_when_idle).await {
452            Ok(how) => reached.push(format!("{label} ({how})")),
453            Err(detail) => failed.push(format!("{label} ({detail})")),
454        }
455    }
456    let shown_id = crate::mailbox::short_id(&envelope.id);
457    let thread = plan
458        .thread
459        .as_ref()
460        .map(|thread| format!(" Thread {}.", crate::mailbox::short_id(&thread.id)))
461        .unwrap_or_default();
462    let mut text = if reached.is_empty() && copied.is_empty() {
463        format!("Not sent: nobody in its thread could be reached.{thread}")
464    } else {
465        let cc = if copied.is_empty() {
466            String::new()
467        } else {
468            format!(" CC (filed, not woken): {}.", copied.join(", "))
469        };
470        format!(
471            "sent to {}.{cc} Message id {shown_id}.{thread} Don't poll; carry on.",
472            if reached.is_empty() {
473                "no one woken".to_string()
474            } else {
475                reached.join(", ")
476            }
477        )
478    };
479    if !failed.is_empty() {
480        text.push_str(&format!(" Not delivered to: {}.", failed.join("; ")));
481    }
482    let code = if reached.is_empty() && copied.is_empty() {
483        EXIT_FAILED
484    } else {
485        0
486    };
487    let mut outcome = Outcome::new(code, text);
488    if code == 0 {
489        outcome.receipt = Some(
490            serde_json::json!({"delivered": true, "message_ids": [envelope.id], "receipt": "agent-mailbox"}),
491        );
492    }
493    outcome
494}
495
496/// What a receiver is called in an outcome: its session name when it runs here, else its address.
497fn recipient_label(homes: &HarnessHomes, address: &MailAddress) -> String {
498    if address.harness == "operator" || address.harness == "board" {
499        return format!("{}@{}", address.session_id, address.machine);
500    }
501    LiveSessions::read(homes)
502        .all()
503        .iter()
504        .find(|session| &session.address == address)
505        .map(|session| session.name.clone())
506        .unwrap_or_else(|| address.to_string())
507}
508
509/// Deliver `envelope` to `to` through its door, waking it: a session on another machine
510/// through Teams, a stopped one here resumed first. Says how it went.
511async fn deliver_woken(
512    homes: &HarnessHomes,
513    envelope: &Envelope,
514    to: &MailAddress,
515    queue: bool,
516    notify_when_idle: bool,
517) -> Result<&'static str, String> {
518    use crate::mail_route::{deliver as route, door_for, Delivered, NoDoor};
519    let door = match door_for(homes, to) {
520        Ok(door) => door,
521        Err(NoDoor::OtherMachine(_)) => {
522            crate::mailbox::deliver_to(to, envelope).map_err(|error| error.to_string())?;
523            return Ok("filed on its machine");
524        }
525        Err(NoDoor::NotRunning) => {
526            // A reply to a closed session resumes it; it is never a new root. Only a session the
527            // mailbox launched is resumed, the way it was launched; any other waits with its mail.
528            crate::mail_agent::file_unread(to, envelope).map_err(|error| error.to_string())?;
529            if !crate::mail_agent::resumable(to) {
530                return Ok(
531                    "stopped; not resumed, since the mailbox did not launch it: the \
532                           message waits in its mailbox",
533                );
534            }
535            crate::mail_agent::resume(to).map_err(|error| format!("not resumed: {error}"))?;
536            let started = std::time::Instant::now();
537            loop {
538                if let Ok(door) = door_for(homes, to) {
539                    break door;
540                }
541                if started.elapsed() > crate::mail_agent::RESUME_WAIT {
542                    return Ok("resumed; the message waits in its mailbox");
543                }
544                tokio::time::sleep(std::time::Duration::from_secs(1)).await;
545            }
546        }
547    };
548    match route(envelope, to, &door, !queue, notify_when_idle).await? {
549        Ok(Delivered::Steered) => Ok("steered into its running turn"),
550        Ok(Delivered::Started) => Ok("started a turn"),
551        Ok(Delivered::Native { busy: true }) => Ok("read at its next tool call"),
552        Ok(Delivered::Native { busy: false }) => Ok("starts its next turn"),
553        Ok(Delivered::Hooked | Delivered::HookWoken) => Ok("in its mailbox, its hook shows it"),
554        Ok(Delivered::Queued) => Ok("waits in its mailbox"),
555        Ok(Delivered::Operator) => Ok("filed"),
556        Ok(Delivered::Already) => Ok("it already had it"),
557        Ok(Delivered::Stored) => Ok("stored; it has no delivery door"),
558        Err(crate::mail_route::Refused::CannotQueueNative) => {
559            Err("idle, and --queue cannot hold a Claude session's mail".into())
560        }
561        Err(crate::mail_route::Refused::TooLong(bytes)) => Err(format!(
562            "{bytes} bytes; the limit is {}",
563            crate::mail_route::MAX_RELAYED_BYTES
564        )),
565    }
566}
567
568/// Replies in one unbroken chain between two sessions beyond which another
569/// reply is refused: two agents trading acknowledgements never stop on their
570/// own, and every message of such a loop answers the one before it. A new
571/// message (no `--re`) starts a chain, so volume alone is never refused.
572const REPLY_CHAIN_LIMIT: usize = 32;
573
574/// Length of a whole message id: its kind, `-`, and 24 hex digits.
575const FULL_ID_LEN: usize = 26;
576
577/// How many messages deep the reply chain ending at `answered` runs, between
578/// `a` and `b`: each message's `in_reply_to`, followed back through both
579/// sessions' mailboxes.
580fn reply_chain_depth(a: &MailAddress, b: &MailAddress, answered: &str) -> usize {
581    let mut links = std::collections::HashMap::new();
582    for address in [a, b] {
583        let Ok(mailbox) = Mailbox::open(&mail_root(), address) else {
584            continue;
585        };
586        for stored in mailbox.list().unwrap_or_default() {
587            links.insert(
588                stored.envelope.id.clone(),
589                stored.envelope.in_reply_to.clone(),
590            );
591        }
592    }
593    let mut depth = 0;
594    let mut current = Some(answered.to_string());
595    while let Some(id) = current {
596        if depth > REPLY_CHAIN_LIMIT || !links.contains_key(&id) {
597            break;
598        }
599        depth += 1;
600        current = links.get(&id).cloned().flatten();
601    }
602    depth
603}
604
605fn send_log(sender: &MailAddress) -> PathBuf {
606    let hash = blake3::hash(sender.to_string().as_bytes()).to_hex();
607    mail_root().join("sent").join(&hash[..24]).join("log.jsonl")
608}
609
610fn record_send(sender: &MailAddress, to: &MailAddress, message_id: &str) {
611    let log = send_log(sender);
612    if let Some(parent) = log.parent() {
613        std::fs::create_dir_all(parent).ok();
614    }
615    if let Ok(mut file) = std::fs::OpenOptions::new()
616        .create(true)
617        .append(true)
618        .open(&log)
619    {
620        use std::io::Write as _;
621        let entry = serde_json::json!({"to": to.to_string(), "at_ms": now_ms(), "id": message_id});
622        writeln!(file, "{entry}").ok();
623    }
624}
625
626fn now_ms() -> u64 {
627    std::time::SystemTime::now()
628        .duration_since(std::time::UNIX_EPOCH)
629        .map(|elapsed| elapsed.as_millis() as u64)
630        .unwrap_or_default()
631}
632
633/// Marker recording that `message_id` was sent by `sender`, for `--id`.
634fn sent_marker(sender: &MailAddress, message_id: &str) -> PathBuf {
635    let hash = blake3::hash(sender.to_string().as_bytes()).to_hex();
636    mail_root().join("sent").join(&hash[..24]).join(message_id)
637}
638
639/// Terminal acknowledgements come from the daemon's retained mailbox receipts,
640/// not the fact that an envelope was filed or a composer became empty.
641fn delivery_receipt(address: &MailAddress, id: &str, terminal: bool) -> serde_json::Value {
642    if !terminal {
643        return serde_json::json!({"delivered": true, "message_ids": [id], "receipt": "native-mail"});
644    }
645    let recipient = format!("{}:{}", address.harness, address.session_id);
646    if let Ok(entries) = std::fs::read_dir(mail_root().join("terminal-delivery")) {
647        for entry in entries.flatten() {
648            let Ok(bytes) = std::fs::read(entry.path().join("queue.json")) else {
649                continue;
650            };
651            let Ok(state) = serde_json::from_slice::<serde_json::Value>(&bytes) else {
652                continue;
653            };
654            if state["recipient"].as_str() != Some(recipient.as_str()) {
655                continue;
656            }
657            if let Some(receipt) = state["receipts"].as_array().and_then(|receipts| {
658                receipts.iter().find(|r| {
659                    r["message_ids"]
660                        .as_array()
661                        .is_some_and(|ids| ids.iter().any(|value| value.as_str() == Some(id)))
662                })
663            }) {
664                return receipt.clone();
665            }
666            return serde_json::json!({"delivered": false, "queued": true, "message_ids": [id], "reason": state["active"]["error"]});
667        }
668    }
669    serde_json::json!({"delivered": false, "queued": true, "message_ids": [id], "reason": "awaiting terminal mailbox"})
670}