feat(mail): add CC and BCC fields to email requests and forms (#466)

* feat(mail): add CC and BCC fields to email requests and forms

* chore: fmt
This commit is contained in:
Abdulrazzaq Alhendi
2026-02-06 03:59:38 +03:00
committed by GitHub
parent 796f6f364a
commit 65d1fdd3f0
13 changed files with 146 additions and 3 deletions

View File

@@ -32,6 +32,12 @@ class SendEstimatesRequest extends FormRequest
'to' => [ 'to' => [
'required', 'required',
], ],
'cc' => [
'nullable',
],
'bcc' => [
'nullable',
],
]; ];
} }
} }

View File

@@ -32,6 +32,12 @@ class SendInvoiceRequest extends FormRequest
'to' => [ 'to' => [
'required', 'required',
], ],
'cc' => [
'nullable',
],
'bcc' => [
'nullable',
],
]; ];
} }
} }

View File

@@ -32,6 +32,12 @@ class SendPaymentRequest extends FormRequest
'to' => [ 'to' => [
'required', 'required',
], ],
'cc' => [
'nullable',
],
'bcc' => [
'nullable',
],
]; ];
} }
} }

View File

@@ -36,6 +36,8 @@ class SendEstimateMail extends Mailable
$log = EmailLog::create([ $log = EmailLog::create([
'from' => $this->data['from'], 'from' => $this->data['from'],
'to' => $this->data['to'], 'to' => $this->data['to'],
'cc' => $this->data['cc'] ?? null,
'bcc' => $this->data['bcc'] ?? null,
'subject' => $this->data['subject'], 'subject' => $this->data['subject'],
'body' => $this->data['body'], 'body' => $this->data['body'],
'mailable_type' => Estimate::class, 'mailable_type' => Estimate::class,

View File

@@ -36,6 +36,8 @@ class SendInvoiceMail extends Mailable
$log = EmailLog::create([ $log = EmailLog::create([
'from' => $this->data['from'], 'from' => $this->data['from'],
'to' => $this->data['to'], 'to' => $this->data['to'],
'cc' => $this->data['cc'] ?? null,
'bcc' => $this->data['bcc'] ?? null,
'subject' => $this->data['subject'], 'subject' => $this->data['subject'],
'body' => $this->data['body'], 'body' => $this->data['body'],
'mailable_type' => Invoice::class, 'mailable_type' => Invoice::class,

View File

@@ -36,6 +36,8 @@ class SendPaymentMail extends Mailable
$log = EmailLog::create([ $log = EmailLog::create([
'from' => $this->data['from'], 'from' => $this->data['from'],
'to' => $this->data['to'], 'to' => $this->data['to'],
'cc' => $this->data['cc'] ?? null,
'bcc' => $this->data['bcc'] ?? null,
'subject' => $this->data['subject'], 'subject' => $this->data['subject'],
'body' => $this->data['body'], 'body' => $this->data['body'],
'mailable_type' => Payment::class, 'mailable_type' => Payment::class,

View File

@@ -374,7 +374,14 @@ class Estimate extends Model implements HasMedia
$this->save(); $this->save();
} }
\Mail::to($data['to'])->send(new SendEstimateMail($data)); $mail = \Mail::to($data['to']);
if (! empty($data['cc'])) {
$mail->cc($data['cc']);
}
if (! empty($data['bcc'])) {
$mail->bcc($data['bcc']);
}
$mail->send(new SendEstimateMail($data));
return [ return [
'success' => true, 'success' => true,

View File

@@ -464,7 +464,14 @@ class Invoice extends Model implements HasMedia
{ {
$data = $this->sendInvoiceData($data); $data = $this->sendInvoiceData($data);
\Mail::to($data['to'])->send(new SendInvoiceMail($data)); $mail = \Mail::to($data['to']);
if (! empty($data['cc'])) {
$mail->cc($data['cc']);
}
if (! empty($data['bcc'])) {
$mail->bcc($data['bcc']);
}
$mail->send(new SendInvoiceMail($data));
if ($this->status == Invoice::STATUS_DRAFT) { if ($this->status == Invoice::STATUS_DRAFT) {
$this->status = Invoice::STATUS_SENT; $this->status = Invoice::STATUS_SENT;

View File

@@ -144,7 +144,14 @@ class Payment extends Model implements HasMedia
{ {
$data = $this->sendPaymentData($data); $data = $this->sendPaymentData($data);
\Mail::to($data['to'])->send(new SendPaymentMail($data)); $mail = \Mail::to($data['to']);
if (! empty($data['cc'])) {
$mail->cc($data['cc']);
}
if (! empty($data['bcc'])) {
$mail->bcc($data['bcc']);
}
$mail->send(new SendPaymentMail($data));
return [ return [
'success' => true, 'success' => true,

View File

@@ -29,6 +29,8 @@
"to_date": "To Date", "to_date": "To Date",
"from": "From", "from": "From",
"to": "To", "to": "To",
"cc": "CC",
"bcc": "BCC",
"ok": "Ok", "ok": "Ok",
"yes": "Yes", "yes": "Yes",
"no": "No", "no": "No",

View File

@@ -42,6 +42,30 @@
@input="v$.to.$touch()" @input="v$.to.$touch()"
/> />
</BaseInputGroup> </BaseInputGroup>
<BaseInputGroup
:label="$t('general.cc')"
:error="v$.cc && v$.cc.$error && v$.cc.$errors[0].$message"
>
<BaseInput
v-model="estimateMailForm.cc"
type="email"
:invalid="v$.cc && v$.cc.$error"
@input="v$.cc && v$.cc.$touch()"
placeholder="Optional: CC recipient"
/>
</BaseInputGroup>
<BaseInputGroup
:label="$t('general.bcc')"
:error="v$.bcc && v$.bcc.$error && v$.bcc.$errors[0].$message"
>
<BaseInput
v-model="estimateMailForm.bcc"
type="email"
:invalid="v$.bcc && v$.bcc.$error"
@input="v$.bcc && v$.bcc.$touch()"
placeholder="Optional: BCC recipient"
/>
</BaseInputGroup>
<BaseInputGroup <BaseInputGroup
:label="$t('general.subject')" :label="$t('general.subject')"
required required
@@ -166,6 +190,8 @@ let estimateMailForm = reactive({
id: null, id: null,
from: null, from: null,
to: null, to: null,
cc: null,
bcc: null,
subject: t('estimates.new_estimate'), subject: t('estimates.new_estimate'),
body: null, body: null,
}) })
@@ -189,6 +215,12 @@ const rules = {
required: helpers.withMessage(t('validation.required'), required), required: helpers.withMessage(t('validation.required'), required),
email: helpers.withMessage(t('validation.email_incorrect'), email), email: helpers.withMessage(t('validation.email_incorrect'), email),
}, },
cc: {
email: helpers.withMessage(t('validation.email_incorrect'), email),
},
bcc: {
email: helpers.withMessage(t('validation.email_incorrect'), email),
},
subject: { subject: {
required: helpers.withMessage(t('validation.required'), required), required: helpers.withMessage(t('validation.required'), required),
}, },

View File

@@ -41,6 +41,30 @@
@input="v$.to.$touch()" @input="v$.to.$touch()"
/> />
</BaseInputGroup> </BaseInputGroup>
<BaseInputGroup
:label="$t('general.cc')"
:error="v$.cc && v$.cc.$error && v$.cc.$errors[0].$message"
>
<BaseInput
v-model="invoiceMailForm.cc"
type="text"
:invalid="v$.cc && v$.cc.$error"
@input="v$.cc && v$.cc.$touch()"
placeholder="Optional: CC recipient"
/>
</BaseInputGroup>
<BaseInputGroup
:label="$t('general.bcc')"
:error="v$.bcc && v$.bcc.$error && v$.bcc.$errors[0].$message"
>
<BaseInput
v-model="invoiceMailForm.bcc"
type="text"
:invalid="v$.bcc && v$.bcc.$error"
@input="v$.bcc && v$.bcc.$touch()"
placeholder="Optional: BCC recipient"
/>
</BaseInputGroup>
<BaseInputGroup <BaseInputGroup
:error="v$.subject.$error && v$.subject.$errors[0].$message" :error="v$.subject.$error && v$.subject.$errors[0].$message"
:label="$t('general.subject')" :label="$t('general.subject')"
@@ -181,6 +205,8 @@ const invoiceMailForm = reactive({
id: null, id: null,
from: null, from: null,
to: null, to: null,
cc: null,
bcc: null,
subject: t('invoices.new_invoice'), subject: t('invoices.new_invoice'),
body: null, body: null,
}) })
@@ -206,6 +232,12 @@ const rules = {
required: helpers.withMessage(t('validation.required'), required), required: helpers.withMessage(t('validation.required'), required),
email: helpers.withMessage(t('validation.email_incorrect'), email), email: helpers.withMessage(t('validation.email_incorrect'), email),
}, },
cc: {
email: helpers.withMessage(t('validation.email_incorrect'), email),
},
bcc: {
email: helpers.withMessage(t('validation.email_incorrect'), email),
},
subject: { subject: {
required: helpers.withMessage(t('validation.required'), required), required: helpers.withMessage(t('validation.required'), required),
}, },

View File

@@ -41,6 +41,30 @@
@input="v$.to.$touch()" @input="v$.to.$touch()"
/> />
</BaseInputGroup> </BaseInputGroup>
<BaseInputGroup
:label="$t('general.cc')"
:error="v$.cc && v$.cc.$error && v$.cc.$errors[0].$message"
>
<BaseInput
v-model="paymentMailForm.cc"
type="email"
:invalid="v$.cc && v$.cc.$error"
@input="v$.cc && v$.cc.$touch()"
placeholder="Optional: CC recipient"
/>
</BaseInputGroup>
<BaseInputGroup
:label="$t('general.bcc')"
:error="v$.bcc && v$.bcc.$error && v$.bcc.$errors[0].$message"
>
<BaseInput
v-model="paymentMailForm.bcc"
type="email"
:invalid="v$.bcc && v$.bcc.$error"
@input="v$.bcc && v$.bcc.$touch()"
placeholder="Optional: BCC recipient"
/>
</BaseInputGroup>
<BaseInputGroup <BaseInputGroup
:error="v$.subject.$error && v$.subject.$errors[0].$message" :error="v$.subject.$error && v$.subject.$errors[0].$message"
:label="$t('general.subject')" :label="$t('general.subject')"
@@ -181,6 +205,8 @@ const paymentMailForm = reactive({
id: null, id: null,
from: null, from: null,
to: null, to: null,
cc: null,
bcc: null,
subject: t('payments.new_payment'), subject: t('payments.new_payment'),
body: null, body: null,
}) })
@@ -206,6 +232,12 @@ const rules = {
required: helpers.withMessage(t('validation.required'), required), required: helpers.withMessage(t('validation.required'), required),
email: helpers.withMessage(t('validation.email_incorrect'), email), email: helpers.withMessage(t('validation.email_incorrect'), email),
}, },
cc: {
email: helpers.withMessage(t('validation.email_incorrect'), email),
},
bcc: {
email: helpers.withMessage(t('validation.email_incorrect'), email),
},
subject: { subject: {
required: helpers.withMessage(t('validation.required'), required), required: helpers.withMessage(t('validation.required'), required),
}, },