## ADDED Requirements

### Requirement: Manual per-invitation send (P0)
An admin holding the send-messages permission SHALL be able to send an invitation email to
one named guest for one invitation, from that guest's detail view, without going through the
bulk send screen. The send SHALL be recorded as a message job like any other send, so it
appears in the message log, carries delivery and bounce receipts, and is written to the audit
log against the acting admin.

#### Scenario: Sending to one guest
- **WHEN** an admin composes and sends an invitation email for a single invitation
- **THEN** the guest receives that email
- **AND** a message job for that invitation records the send with its provider message id
- **AND** the audit log records the acting admin, the invitation and the time

#### Scenario: Appears in the message log
- **WHEN** a manual send has been made
- **THEN** it is listed in the admin message log with the same statuses as automated sends
- **AND** a later delivery or bounce receipt updates it the same way

#### Scenario: Permission required
- **WHEN** an admin without the send-messages permission requests a manual send
- **THEN** the request is refused by the API regardless of what the interface offered

### Requirement: Server-composed message defaults (P0)
The system SHALL compose the default message for a manual send on the server and return it as
four editable parts: a subject, a header addressing the guest by name, a body, and a footer
naming the host. The body SHALL be the invitation message that applies to this guest —
resolved for the guest's invitation type (single or family/multiple) through the event's
message, then the wedding-wide message, then the built-in default — followed by that guest's
personal invitation link. The composed default SHALL be rendered in the guest's preferred
locale.

#### Scenario: Single guest
- **WHEN** the default message is composed for a guest whose invitation type is single
- **THEN** the body carries the single-guest message that applies to their event

#### Scenario: Family guest
- **WHEN** the default message is composed for a guest whose invitation type is family
- **THEN** the body carries the family/multiple message that applies to their event

#### Scenario: Event override respected
- **WHEN** the guest's event stores its own invitation message
- **THEN** the composed body uses the event's message rather than the wedding-wide one

#### Scenario: Nothing customised
- **WHEN** neither the event nor the wedding stores a message for this type and locale
- **THEN** the composed body uses the built-in default and is never empty

#### Scenario: Link included
- **WHEN** any default message is composed
- **THEN** it contains that guest's personal invitation link

### Requirement: Admin-edited message content (P0)
Every part of the composed message — subject, header, body and footer — SHALL be editable
before sending, and the edited text SHALL be what is delivered. Edits SHALL apply to that one
send only and SHALL NOT change the event's or the wedding's stored invitation messages. The
delivered message SHALL carry the unsubscribe line regardless of what the admin edited.

#### Scenario: Edited text is delivered
- **WHEN** an admin edits the body and sends
- **THEN** the guest receives the edited body, not the composed default

#### Scenario: Edits do not persist
- **WHEN** an admin edits a message and sends it, then composes a message for another guest of the same event
- **THEN** the second composition shows the event's stored message, unaffected by the first edit

#### Scenario: Unsubscribe survives editing
- **WHEN** an admin removes the unsubscribe wording from the body and sends
- **THEN** the delivered email still carries a working unsubscribe link for that event

#### Scenario: Empty message rejected
- **WHEN** an admin sends with an empty subject or an empty body
- **THEN** the send is refused with a message naming the empty part, and nothing is queued

### Requirement: Repeatable manual sends (P0)
A manual send SHALL be repeatable: a second manual send to the same invitation SHALL be
delivered rather than silently discarded as a duplicate. The interface SHALL show when that
invitation was last emailed so a repeat is visible before it is sent. Repeatability SHALL NOT
weaken duplicate protection for automated sends.

#### Scenario: Resending after a lost email
- **WHEN** an admin sends a manual invitation to a guest who has already received one
- **THEN** the second email is delivered and recorded as its own message job

#### Scenario: Last-sent visible
- **WHEN** an admin opens the compose panel for an invitation that has been emailed before
- **THEN** the panel states when that invitation was last emailed

#### Scenario: Automated duplicate protection intact
- **WHEN** a reminder wave is planned twice for the same invitation and schedule
- **THEN** exactly one reminder job exists, as before

### Requirement: Quiet hours on a manual send (P0)
A manual send inside quiet hours SHALL warn the admin, naming the local time, and SHALL be
delivered immediately on explicit confirmation rather than deferred. Automated and scheduled
sends SHALL keep deferring past quiet hours unchanged.

#### Scenario: Warned inside quiet hours
- **WHEN** an admin sends a manual invitation at 23:30 local time
- **THEN** they are warned that it is outside sending hours, naming the local time
- **AND** the email is sent only after they confirm

#### Scenario: Sent immediately on confirmation
- **WHEN** the admin confirms a manual send inside quiet hours
- **THEN** the email goes out then, not at the next morning's opening time

#### Scenario: No warning outside quiet hours
- **WHEN** an admin sends a manual invitation at 14:00 local time
- **THEN** no warning is shown and the email is sent on the first click

#### Scenario: Automated waves still defer
- **WHEN** a reminder wave becomes due inside quiet hours
- **THEN** it is deferred to the next opening time, as before

### Requirement: Suppression is not overridable by a manual send (P0)
A manual send SHALL be refused for a guest with no email address, a guest whose address has
hard-bounced, and a guest who has opted out of that event. The interface SHALL disable the
send control and state which of these applies. No confirmation SHALL make a suppressed send
proceed.

#### Scenario: No address
- **WHEN** the guest has no email address
- **THEN** the send control is disabled and says so, and the API refuses the send

#### Scenario: Opted out
- **WHEN** the guest has opted out of this event
- **THEN** the send control is disabled and names the opt-out, and the API refuses the send

#### Scenario: Hard-bounced address
- **WHEN** the guest's address previously hard-bounced
- **THEN** the send control is disabled and names the bounce, and the API refuses the send

#### Scenario: API is the authority
- **WHEN** a manual send is requested for a suppressed guest by any means
- **THEN** the API refuses it and no message job reaches the provider

### Requirement: Immediate outcome reporting (P0)
A manual send SHALL report its real outcome to the admin in the same interaction — delivered
to the provider, failed with the provider's reason, refused, or logged as a dry run — rather
than reporting only that it was queued.

#### Scenario: Success
- **WHEN** the provider accepts the message
- **THEN** the admin sees that it was sent, and when

#### Scenario: Provider failure
- **WHEN** the provider rejects the message or is unreachable
- **THEN** the admin sees that it failed and why, and the message job records the error

#### Scenario: Dry run
- **WHEN** dry-run mode is enabled
- **THEN** nothing is sent and the admin is told plainly that this was a rehearsal, not a delivery

#### Scenario: Provider not configured
- **WHEN** no email provider credentials are configured
- **THEN** the send fails with a message naming the missing configuration rather than a provider error

### Requirement: Host reply address (P1)
Outbound email SHALL be sent from the platform's authenticated sender address, and SHALL set
a reply address to the wedding's host email when one is configured, so a guest's reply
reaches the couple rather than the platform.

#### Scenario: Reply reaches the host
- **WHEN** a host email is configured and a guest replies to any invitation email
- **THEN** the reply is addressed to the host email

#### Scenario: No host email configured
- **WHEN** no host email is configured
- **THEN** email is sent as before, with no reply address set, and no send fails for its absence

#### Scenario: Sender identity unchanged
- **WHEN** any email is sent
- **THEN** its from address is the platform's configured sender, so domain authentication still passes
