Email flows
Flow 1: Quote submission
When a client submits a quote viaPOST /api/quotes/submit, two emails are sent by QuoteApiController::submitQuote():
Client confirmation (QuoteReceived)
QuoteReceived is sent to quote->client_email with the subject "Cotización recibida - {reference}" and the generated PDF attached.The admin notification recipient is read from
config('mail.admin_email'). Set this key in config/mail.php or via an environment variable to ensure the DMI team receives submission alerts.Flow 2: Admin reply (meeting scheduling)
Admin schedules a meeting
In the admin panel, the DMI team opens a quote at
/admin/cotizaciones/{id} and submits the reply form with a meeting_date value (datetime string).Reply is recorded
A
QuoteReply record is created with the formatted meeting message stored in message and the scheduled datetime in sent_at.PDF is regenerated
The quote’s PDF is rebuilt from the stored
Quote and QuoteItem data and written to storage/app/public/quotes/{reference}.pdf.Route
auth and verified middleware. The only required request field is meeting_date (validated as a date).
The meeting message format
The message text is generated byQuoteController::formatMeetingMessage():
2026-03-20 14:30:00 produces:
QuoteReplyMail and rendered in the email view at resources/views/emails/quote-reply.blade.php.
Mailables reference
QuoteReceived
App\Mail\QuoteReceived is sent to the client immediately after they submit a quote. It uses a Markdown template and attaches the generated PDF.
| Property | Value |
|---|---|
| Subject | Cotización recibida - {reference} |
| To | quote->client_email |
| View | emails.quote.received (Markdown) |
| Attachment | cotizacion.pdf (from storage/app/public/{pdf_path}) |
QuoteAdminNotification
App\Mail\QuoteAdminNotification is sent to the DMI team when a new quote arrives. It uses a Markdown template and includes quote summary data.
| Property | Value |
|---|---|
| Subject | 📋 Nueva cotización recibida: {reference} |
| To | config('mail.admin_email') |
| View | emails.quote.admin-notification (Markdown) |
| Variables | $quote, $blocks, $totalHours, $totalCost |
The QuoteReplyMail mailable
App\Mail\QuoteReplyMail extends Laravel’s Mailable class and uses the Queueable and SerializesModels traits.
| Property | Description |
|---|---|
| Subject | Tu cotización y cita virtual (fixed) |
| To | quote->client_email |
| View | emails.quote-reply |
| Attachment name | {quote->reference}.pdf |
| Attachment path | storage/app/public/{pdfPath} |
QuoteReplyMail implements Queueable but is dispatched synchronously via Mail::to()->send(). To queue it, change send() to queue() and ensure a queue worker is running.Configuring SMTP in .env
By default, ElCoco uses the log mailer, which writes emails to storage/logs/laravel.log instead of sending them. Change MAIL_MAILER to smtp for real delivery.
- Local development (log)
- Mailgun
- Gmail SMTP
- Mailtrap (staging)
storage/logs/laravel.log. No SMTP server required.All mail environment variables
| Variable | Default | Description |
|---|---|---|
MAIL_MAILER | log | Transport driver. Use smtp for real delivery |
MAIL_SCHEME | null | TLS scheme: blank (STARTTLS), ssl, or tls |
MAIL_HOST | 127.0.0.1 | SMTP server hostname |
MAIL_PORT | 2525 | SMTP port (587 for STARTTLS, 465 for SSL) |
MAIL_USERNAME | null | SMTP authentication username |
MAIL_PASSWORD | null | SMTP authentication password |
MAIL_FROM_ADDRESS | [email protected] | Sender From: address |
MAIL_FROM_NAME | ${APP_NAME} | Sender From: display name |
Test email route
A development-only route is registered inroutes/web.php for quickly verifying your mail configuration:
Supported mail transports
Laravel’sconfig/mail.php lists all available transports. You can switch between them without code changes:
smtp
smtp
Standard SMTP. Works with any SMTP-compatible provider (Mailgun, Postmark, SendGrid, Gmail, etc.).
log
log
Writes the email content to the Laravel log. Default for local development. Useful for inspecting email output without a mail server.
ses
ses
Amazon Simple Email Service. Requires
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and the aws/aws-sdk-php package.postmark
postmark
Postmark transactional email. Requires the
postmark/postmark-php package and a POSTMARK_TOKEN.resend
resend
Resend email API. Requires the
resend/resend-laravel package and a RESEND_KEY.failover
failover
Tries
smtp first; falls back to log if delivery fails. Configured in config/mail.php.