A handler must be idempotent, because delivery is at-least-once

Every broker worth using delivers at least once, so a handler will see the same message twice — on a redelivery after a crash, or when an acknowledgement is lost.

public function handle(SendReceipt $message): void
{
    // the unique index arbitrates. a SELECT does not.
    try {
        DB::table('receipts_sent')->insert(['order_id' => $message->orderId]);
    } catch (QueryException $e) {
        if ($this->isDuplicateKey($e)) {
            return;      // already done
        }

        throw $e;
    }

    Mail::to($this->emailFor($message->orderId))->send(new Receipt());
}

Recording before the side effect rather than after is the ordering that matters: a receipt recorded after a successful send is not recorded when the process dies between the two. Recording first means a crash after the insert loses one email, which is the better failure. There is no ordering that gets both, which is the honest summary of exactly-once delivery.