# Email Configuration Module

## Overview

The Email Configuration module allows each organization to configure their own SMTP settings for sending recruitment and system emails. This provides better branding, deliverability, and control over email communications.

**Version**: 1.0  
**Added**: February 2026

---

## Features

### Core Functionality
- ✅ Organization-specific SMTP configuration
- ✅ Support for multiple email providers
- ✅ Test email functionality
- ✅ Secure credential storage
- ✅ Automatic fallback to system defaults
- ✅ Real-time configuration validation
- ✅ Email delivery monitoring

---

## Configuration

### Access Email Settings

**URL**: `/settings/email-setup`

**Required Permission**: `edit_organization_settings` or `edit_email_settings`

**Navigation**: Settings → Email Settings

### Configuration Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| Use Custom Mail | Boolean | Yes | Enable/disable custom email |
| Mail Driver | Select | Yes* | Email driver (smtp, sendmail, etc.) |
| Mail Host | String | Yes* | SMTP server hostname |
| Mail Port | Integer | Yes* | SMTP server port |
| Mail Username | String | No | SMTP username |
| Mail Password | Password | No | SMTP password |
| Mail Encryption | Select | Yes* | Encryption type (tls, ssl, none) |
| From Email Address | Email | Yes* | Sender email address |
| From Name | String | Yes* | Sender name |

*Required when "Use Custom Mail" is enabled

---

## Supported Email Providers

### Gmail

**Configuration**:
```yaml
Mail Host: smtp.gmail.com
Mail Port: 587
Encryption: TLS
Username: your-email@gmail.com
Password: [App Password]
From Email: your-email@gmail.com
From Name: Your Organization
```

**Setup Steps**:
1. Go to [Google Account Security](https://myaccount.google.com/security)
2. Enable 2-Step Verification
3. Go to App Passwords
4. Select "Mail" and generate password
5. Use generated password (not your regular password)

**Important Notes**:
- Must use App Password, not regular password
- 2-Step Verification must be enabled
- App Password is 16 characters without spaces
- Each app password is unique

**Troubleshooting**:
- Error "Username and Password not accepted": Use App Password
- Error "Less secure app": Enable 2-Step Verification and use App Password
- Emails not sending: Check App Password is correct

### Microsoft 365 / Outlook

**Configuration**:
```yaml
Mail Host: smtp.office365.com
Mail Port: 587
Encryption: TLS
Username: your-email@yourcompany.com
Password: [Your email password]
From Email: your-email@yourcompany.com
From Name: Your Organization
```

**Setup Steps**:
1. Use your Microsoft 365 email address
2. Use your regular email password
3. Ensure SMTP is enabled in Microsoft 365 admin

**Important Notes**:
- Works with Microsoft 365 Business accounts
- May require admin approval for SMTP
- Check with IT department if issues occur

**Troubleshooting**:
- Error "Authentication failed": Verify password is correct
- Error "SMTP disabled": Contact Microsoft 365 admin
- Emails not sending: Check account has SMTP enabled

### SendGrid

**Configuration**:
```yaml
Mail Host: smtp.sendgrid.net
Mail Port: 587
Encryption: TLS
Username: apikey
Password: [Your SendGrid API Key]
From Email: verified-sender@yourcompany.com
From Name: Your Organization
```

**Setup Steps**:
1. Create [SendGrid account](https://sendgrid.com)
2. Verify sender email address
3. Create API Key with "Mail Send" permission
4. Use "apikey" as username (literally the word "apikey")
5. Use API Key as password

**Important Notes**:
- Username must be "apikey" (not your email)
- Password is your API Key
- Sender email must be verified in SendGrid
- Free tier: 100 emails/day

**Troubleshooting**:
- Error "Authentication failed": Check API Key is correct
- Error "Sender not verified": Verify sender email in SendGrid
- Emails not sending: Check API Key has Mail Send permission

### Mailgun

**Configuration**:
```yaml
Mail Host: smtp.mailgun.org
Mail Port: 587
Encryption: TLS
Username: postmaster@your-domain.mailgun.org
Password: [Your Mailgun SMTP password]
From Email: noreply@your-domain.com
From Name: Your Organization
```

**Setup Steps**:
1. Create [Mailgun account](https://mailgun.com)
2. Add and verify your domain
3. Get SMTP credentials from domain settings
4. Use provided SMTP username and password

**Important Notes**:
- Domain must be verified
- Free tier: 5,000 emails/month for 3 months
- Username format: postmaster@your-domain.mailgun.org

**Troubleshooting**:
- Error "Domain not verified": Verify domain in Mailgun
- Error "Authentication failed": Check SMTP credentials
- Emails not sending: Check domain DNS records

### Amazon SES

**Configuration**:
```yaml
Mail Host: email-smtp.us-east-1.amazonaws.com
Mail Port: 587
Encryption: TLS
Username: [Your SMTP username]
Password: [Your SMTP password]
From Email: verified-email@yourcompany.com
From Name: Your Organization
```

**Setup Steps**:
1. Create AWS account
2. Set up Amazon SES
3. Verify email address or domain
4. Create SMTP credentials
5. Move out of sandbox mode (for production)

**Important Notes**:
- Email/domain must be verified
- Sandbox mode: Can only send to verified emails
- Production mode: Can send to any email
- Region-specific SMTP endpoints

### Custom SMTP Server

**Configuration**:
```yaml
Mail Host: [Your SMTP server]
Mail Port: [Your SMTP port]
Encryption: [tls|ssl|none]
Username: [Your username]
Password: [Your password]
From Email: [Your email]
From Name: [Your name]
```

**Common Ports**:
- **587**: TLS (recommended)
- **465**: SSL
- **25**: Unencrypted (not recommended)

---

## Email Types

All emails now use organization-specific settings:

### Recruitment Emails

1. **Application Received**
   - Sent to: Candidate
   - Trigger: Application submission
   - Content: Confirmation with tracking link

2. **Application Status Changed**
   - Sent to: Candidate
   - Trigger: Status update
   - Content: New status with details

3. **Interview Invitation**
   - Sent to: Candidate
   - Trigger: Interview scheduled
   - Content: Interview details with confirmation link

4. **Interview Scheduled**
   - Sent to: Candidate
   - Trigger: Interview confirmed
   - Content: Final interview details

5. **Job Offer Sent**
   - Sent to: Candidate
   - Trigger: Offer created
   - Content: Offer details with acceptance link

6. **New Message from HR**
   - Sent to: Candidate
   - Trigger: HR sends message
   - Content: Message with reply link

7. **New Message from Candidate**
   - Sent to: HR
   - Trigger: Candidate sends message
   - Content: Message with reply link

### Employee Emails

8. **Welcome New Employee**
   - Sent to: New employee
   - Trigger: Offer accepted
   - Content: Welcome message with login details

---

## Testing Email Configuration

### Test Before Saving

1. Enter all email settings
2. Enter test email address
3. Click "Send Test"
4. Check inbox for test email
5. If successful, save settings

### Test Email Content

```
Subject: Test Email - [Organization Name]

This is a test email from [Organization Name].

If you received this email, your email configuration is working correctly.

Email Settings:
- Mail Host: smtp.gmail.com
- Mail Port: 587
- Encryption: TLS
- From: noreply@yourcompany.com

Sent at: [Timestamp]
```

### Test Command

```bash
# Test all recruitment emails
php artisan recruitment:test-emails your-email@example.com

# Test with specific application
php artisan recruitment:test-emails your-email@example.com --application-id=1

# Test with specific job posting
php artisan recruitment:test-emails your-email@example.com --job-posting-id=1
```

---

## Technical Implementation

### Database Schema

**Organizations Table**:
```sql
ALTER TABLE organizations ADD COLUMN (
  use_custom_mail BOOLEAN DEFAULT FALSE,
  mail_driver VARCHAR(255) DEFAULT 'smtp',
  mail_host VARCHAR(255),
  mail_port INTEGER DEFAULT 587,
  mail_username VARCHAR(255),
  mail_password VARCHAR(255),
  mail_encryption VARCHAR(255) DEFAULT 'tls',
  mail_from_address VARCHAR(255),
  mail_from_name VARCHAR(255)
);
```

### Service Class

**OrganizationMailService**:
```php
namespace App\Services;

class OrganizationMailService
{
    /**
     * Configure mail for organization
     */
    public static function configureForOrganization(Organization $organization): void
    {
        if (!$organization->use_custom_mail) {
            return;
        }

        Config::set('mail.mailers.smtp', [
            'transport' => 'smtp',
            'host' => $organization->mail_host,
            'port' => $organization->mail_port,
            'encryption' => $organization->mail_encryption,
            'username' => $organization->mail_username,
            'password' => $organization->mail_password,
            'timeout' => null,
        ]);

        Config::set('mail.from', [
            'address' => $organization->mail_from_address,
            'name' => $organization->mail_from_name,
        ]);

        Mail::purge('smtp');
    }

    /**
     * Test configuration
     */
    public static function testConfiguration(Organization $organization, string $testEmail): bool
    {
        try {
            self::configureForOrganization($organization);
            
            Mail::raw('Test email', function ($message) use ($testEmail) {
                $message->to($testEmail)->subject('Test Email');
            });

            return true;
        } catch (\Exception $e) {
            \Log::error('Email test failed: ' . $e->getMessage());
            return false;
        }
    }
}
```

### Mail Class Pattern

**Using Organization Settings**:
```php
namespace App\Mail;

use App\Mail\Concerns\UsesOrganizationMailSettings;

class ApplicationReceived extends Mailable implements ShouldQueue
{
    use Queueable, SerializesModels, UsesOrganizationMailSettings;

    public function __construct(Application $application, JobPosting $jobPosting)
    {
        $this->application = $application;
        $this->jobPosting = $jobPosting;
    }

    protected function getOrganization()
    {
        return $this->jobPosting->organization ?? null;
    }

    public function envelope(): Envelope
    {
        $organization = $this->getOrganization();
        
        $fromAddress = $organization && $organization->use_custom_mail
            ? $organization->mail_from_address
            : config('mail.from.address');
            
        return new Envelope(
            subject: 'Application Received',
            from: $fromAddress,
        );
    }
}
```

---

## Security

### Password Storage

- Passwords stored in database
- Consider encrypting at application level
- Use Laravel's encryption if needed
- Rotate passwords regularly

### Access Control

- Only organization admins can modify settings
- Permissions: `edit_organization_settings` or `edit_email_settings`
- Audit log for configuration changes
- Two-factor authentication recommended

### Best Practices

1. Use dedicated email for system notifications
2. Use App Passwords for Gmail (never regular password)
3. Rotate SMTP credentials regularly
4. Monitor email delivery rates
5. Set up SPF/DKIM records
6. Use TLS encryption
7. Keep credentials secure
8. Limit access to email settings

---

## Monitoring

### Email Delivery

**Check Queue**:
```bash
# View queue jobs
php artisan queue:work --once

# Check failed jobs
php artisan queue:failed

# Retry failed jobs
php artisan queue:retry all

# Clear failed jobs
php artisan queue:flush
```

**Check Logs**:
```bash
# View Laravel logs
tail -f storage/logs/laravel.log

# Filter email logs
tail -f storage/logs/laravel.log | grep -i mail

# Check for errors
tail -f storage/logs/laravel.log | grep -i error
```

### Metrics to Monitor

- Email delivery rate
- Bounce rate
- Spam complaints
- Queue processing time
- Failed job count
- SMTP connection errors

---

## Troubleshooting

### Common Issues

#### Authentication Failed

**Symptoms**:
- Error: "Username and Password not accepted"
- Error: "Authentication failed"
- Emails not sending

**Solutions**:
1. **Gmail**: Use App Password, not regular password
2. **Microsoft**: Verify password is correct
3. **SendGrid**: Username must be "apikey"
4. **All**: Check credentials are correct

#### Connection Timeout

**Symptoms**:
- Error: "Connection timed out"
- Error: "Could not connect to SMTP host"
- Long delays before error

**Solutions**:
1. Check firewall allows outbound SMTP
2. Verify port 587 is open
3. Try port 465 with SSL
4. Check mail host is correct
5. Test from command line: `telnet smtp.gmail.com 587`

#### Emails Not Received

**Symptoms**:
- Test email successful but emails not received
- No errors in logs
- Queue processing normally

**Solutions**:
1. Check spam/junk folder
2. Verify "from" email is valid
3. Check email provider logs
4. Verify domain SPF/DKIM records
5. Check recipient email is correct

#### Queue Not Processing

**Symptoms**:
- Emails stuck in queue
- Failed jobs increasing
- No emails being sent

**Solutions**:
1. Start queue worker: `php artisan queue:work`
2. Check queue connection: `php artisan queue:work --once`
3. Restart queue: `php artisan queue:restart`
4. Check failed jobs: `php artisan queue:failed`
5. Clear failed jobs: `php artisan queue:flush`

#### Emails Going to Spam

**Symptoms**:
- Emails delivered but in spam folder
- Low delivery rate
- Spam complaints

**Solutions**:
1. Configure SPF records for domain
2. Set up DKIM signing
3. Use verified sender email
4. Warm up sending domain
5. Avoid spam trigger words
6. Include unsubscribe link

---

## Best Practices

### Configuration

1. **Test Before Production**
   - Test with personal email first
   - Verify all email types work
   - Check spam folder
   - Test queue processing

2. **Use Dedicated Email**
   - Don't use personal email
   - Use noreply@ or notifications@
   - Set up email forwarding if needed
   - Monitor inbox for bounces

3. **Secure Credentials**
   - Use App Passwords for Gmail
   - Rotate passwords regularly
   - Don't share credentials
   - Use environment variables for sensitive data

4. **Monitor Delivery**
   - Check delivery rates daily
   - Monitor bounce rates
   - Review spam complaints
   - Track failed jobs

### Email Content

1. **Professional Formatting**
   - Use organization branding
   - Include contact information
   - Add unsubscribe link
   - Use responsive design

2. **Clear Subject Lines**
   - Be specific and clear
   - Include organization name
   - Avoid spam trigger words
   - Keep under 50 characters

3. **Actionable Content**
   - Clear call-to-action
   - Include relevant links
   - Provide contact information
   - Set expectations

---

## API Reference

### Endpoints

```
GET    /settings/email-setup          - View email settings
PUT    /settings/email-setup          - Update email settings
POST   /settings/email-setup/test     - Test email configuration
```

### Request Examples

**Update Email Settings**:
```http
PUT /settings/email-setup
Content-Type: application/json

{
  "use_custom_mail": true,
  "mail_driver": "smtp",
  "mail_host": "smtp.gmail.com",
  "mail_port": 587,
  "mail_username": "your-email@gmail.com",
  "mail_password": "your-app-password",
  "mail_encryption": "tls",
  "mail_from_address": "noreply@yourcompany.com",
  "mail_from_name": "Your Company"
}
```

**Test Email Configuration**:
```http
POST /settings/email-setup/test
Content-Type: application/json

{
  "test_email": "test@example.com",
  "use_custom_mail": true,
  "mail_host": "smtp.gmail.com",
  "mail_port": 587,
  "mail_username": "your-email@gmail.com",
  "mail_password": "your-app-password",
  "mail_encryption": "tls",
  "mail_from_address": "noreply@yourcompany.com",
  "mail_from_name": "Your Company"
}
```

---

## Support

For issues or questions:
- Review [Troubleshooting Guide](../TROUBLESHOOTING.md)
- Check [FAQ](../FAQ.md)
- Check [CHANGELOG](../CHANGELOG.md)
- Contact system administrator

---

**Module Version**: 1.0  
**Last Updated**: February 8, 2026  
**Documentation Status**: Complete
