Email workspaceEmployee payroll welcome contract
Implementation: App\Mail\welcomeEmployee. View: resources/views/emails/payroll/welcomeEmployee.blade.php. Shared original wrapper: mail::message. Purpose: tell an employee that their employer registered them on Built and provide their payroll-portal login details.
Usage evidence: app/Http/Controllers/Payroll/employeesController.php:348; app/Imports/EmployeeImport.php:57; app/Imports/EmployeeImportKE.php:65; app/Jobs/ImportEmployeesBulkJob.php:186. These static references are evidence, not proof of current production delivery.
Suggested subject: {{subject_business_name}}: Your Registration (existing business-name header pattern).
Suggested preheader: Your employer registered you on Built. Your payroll portal sign-in details are included.
Portable placeholder contract
| Token | Existing source / derivation | Handling |
|---|---|---|
| {{logo_url}} | Original Built app_name PNG | Optional deployment override; concrete project HTTPS PNG is already present. Approved absolute HTTPS or matching attached CID only. |
| {{preheader}} | Suggested text above, based only on existing registration/access context | Required escaped text; no invented expiry or activation claim. |
| {{first_name}} | $employee->first_name | Required escaped employee first name, not the employer or staff sender. |
| {{company_name}} | $payroll_settings->Company_name | Required escaped employer display name, preserving capitalization in the actual source field. Not automatically the business.name used in headers. |
| {{employee_email}} | $email, bound from $employee->email | Required escaped payroll login identifier. Same recipient in the direct path; do not use the employer's email. |
| {{portal_password}} | $password constructor argument -> password view binding | Required original supplied value converted to string only for text output. Preserve leading zeros and all characters. This is not employee.password, which stores the bcrypt hash. Never insert a hash or regenerate a password in the view. |
| {{portal_url}} | Existing literal https://payroll.built.africa/login | Required validated complete HTTPS login destination. The button and visible fallback use this same value. No new reset/setup or token URL. |
Source-only header value {{subject_business_name}} maps to the constructor business.name. It is not a required body token and is not currently passed in the Mailable's view-data array. It sets the existing subject pattern and business From display name; keep it separate from company_name.
Direct and bulk delivery
- Employee creation checks email format then explicitly queues welcomeEmployee. EmployeeImport and EmployeeImportKE also explicitly queue it when the new employee has an email. The Mailable uses Queueable but does not itself implement ShouldQueue; the caller establishes these queued sends.
- Keep the existing subject business.name + ': Your Registration', From configured mail address with business name, and Reply-To business.email ?? owner.email. Preserve null-coalescing behavior rather than silently changing fallback semantics.
- ImportEmployeesBulkJob implements ShouldQueue, inserts employees, obtains per-employee supplied passwords, and renders welcomeEmployee through build()->render(). It sends email/content pairs to EmailHelper::sendBulkEmails with separately assembled subject/reply_to/from. EmailHelper hands bulk data to the external delivery/scheduler service; this design does not change the provider or schedule. API-owned HTML remains in scope.
- The bulk payload currently carries rendered HTML, not a separately supplied plain-text alternative. The proposed .txt file needs an explicit provider-payload decision during later integration; do not claim it is automatically delivered.
- The direct controller/importers and bulk job create passwords differently. Keep the supplied password consistent with existing stored credentials; the template is not the place to change generation or bcrypt storage. Previews contain clearly synthetic demo values and example.com addresses only.
- No PDF or other attachment exists in this Mailable. No copy/BCC route is invented. The legacy welcomeemployeeJob uses mails.welcomeemployee, with dispatch unresolved in the catalog, and is not treated as another live signup notification.
Content and workflow fidelity
Keep the greeting, employer registration context, complete email/password instructions and portal URL. Open payroll portal is a clearer primary action for the source's visible login URL. It opens login; it is not a signup, password reset, approval or payroll-payment action.
This body currently sends a password. The draft preserves that existing field as an explicit contract; it does not assert that it is temporary, one-use, expired after a period or subject to a mandatory first-login change. A setup-link alternative needs a separately authorized authentication workflow. Review this inherited password-delivery choice before production integration rather than silently dropping the access instruction or fabricating a setup endpoint.
States: direct registration with differing employer/business identities; bulk import using the same body; leading-zero synthetic string; and long values. Direct/bulk are delivery/data fixtures for one notification type, not separate template requirements. There are no optional blocks or supported blank-password states. Decide missing required values upstream; do not invent an employee identity or truncate the details.
Safe integration, images and text
ready/employee-welcome.html and ready/employee-welcome.txt are portable extracts. Every populated state has HTML/text under previews/. Portable {{placeholder_name}} syntax does not automatically reference Laravel variables. Prefer a dedicated full Blade HTML view with explicitly mapped existing values and a text() alternative in the existing Mailable. Do not nest a full document inside mail::message or introduce another templating framework.
Escape every text/attribute value. Preserve the supplied password literally as text after HTML escaping; do not trim it, turn it into a number, mask it, insert raw HTML or evaluate inserted token-looking text again. If string replacement is chosen, use one pass. Validate portal_url separately to the intended HTTPS payroll host/login path before attribute escaping it. The added fallback duplicates the same existing portal URL; there is no second legacy link field to reconcile.
Default logo: https://built-storage.ams3.cdn.digitaloceanspaces.com/Built/app_name.png. Retain assets/built-logo.png as the unchanged source. Use absolute HTTPS hosting or a real matching CID attachment and preserve proportions. Validate deployment overrides separately; remote images can be blocked. The logo's white backing supports the existing navy asset in dark mode.
No separate project-owned plain-text alternative was found for the source Markdown view; the supplied text is a proposed equivalent. No sample link logs in, resets a password or contacts a live employee. No production files, credential generation/storage, sender/queue/provider behavior or application actions are changed. Native dark CSS and browser checks do not establish Gmail, Outlook or iOS Mail compatibility. See employee-onboarding-batch.md and employee-onboarding-validation.md.