# Email Sending – CI4 (SMTP, UTF-8, Debugging)

## 1. Why "250-SMTPUTF8" is not an error

- **250-SMTPUTF8** is an SMTP **capability line** from the server (e.g. “I support SMTPUTF8”).
- Lines like `220 ...`, `250-...`, `250 OK`, `334 ...`, `235 ...` are normal SMTP handshake/response lines.
- The app was treating the last non-filtered line as the “error” and sometimes showed `250-SMTPUTF8` instead of the real failure.
- **Fix:** Error extraction now skips all lines that start with `250-`, `250 `, `220 `, etc. (pattern `^\d{3}[\s-]`), so only real error messages are shown to the user.

## 2. Root cause of the issue

- **Misidentified “error”:** The flash message was showing an SMTP capability line (`250-SMTPUTF8`) as if it were the error.
- **Real failures** are usually one of:
  - Missing or invalid **setFrom()**
  - Wrong SMTP **host / port / user / pass** in `.env`
  - **Port blocked** (e.g. 25 blocked; use 587 or 2525)
  - **Auth failure** (wrong user/pass or API key)
  - **Charset/encoding** (handled by using UTF-8 and `setCharset('UTF-8')`)

## 3. Production-ready Email config

- **File:** `app/Config/Email.php`
- Uses **SMTP** via `.env` (no `mail()`).
- **UTF-8:** `charset = 'UTF-8'` and `setCharset('UTF-8')` in sending code.
- **Gmail:** port 587, tls. **SendGrid:** port 2525 or 587, tls.
- **Always call `setFrom($address, $name)`** in your code; config `fromEmail`/`fromName` are optional fallbacks.

## 4. .env (SMTP)

```env
# Required for SMTP
email.protocol = smtp
email.SMTPHost = smtp.sendgrid.net
email.SMTPUser = apikey
email.SMTPPass = your_sendgrid_api_key
email.SMTPPort = 2525
email.SMTPCrypto = tls

# Optional defaults (override with setFrom() in code)
# email.fromEmail = noreply@yoursite.com
# email.fromName = Your App Name
```

**Gmail example:**

```env
email.protocol = smtp
email.SMTPHost = smtp.gmail.com
email.SMTPUser = your@gmail.com
email.SMTPPass = app_password
email.SMTPPort = 587
email.SMTPCrypto = tls
```

## 5. Working email sending example (Services::email)

```php
use Config\Services;

$email = Services::email();

$email->clear(true);
$email->setFrom('sender@example.com', 'Sender Name');  // Required
$email->setTo('recipient@example.com');
$email->setSubject('Subject');
$email->setMailType('html');
$email->setMessage('<p>Hello, world.</p>');

if (!$email->send(false)) {
    log_message('error', 'Email failed: ' . $email->printDebugger(['headers', 'subject', 'body']));
    // Show user a short message; full debug is in the log
    return false;
}
return true;
```

## 6. Debugging with printDebugger()

- **On failure**, the full debug output is written to the log (see `UtilityModel::send_mail()`).
- To inspect it:
  1. Check `writable/logs/log-YYYY-MM-DD.log` for `Email send failed. Debug: ...`.
  2. Or temporarily in code:  
     `$debug = $email->printDebugger(['headers', 'subject', 'body']);`  
     then `log_message('error', $debug);` or return it in dev only.
- **Ignore** lines like `220 ...`, `250-SMTPUTF8`, `hello:`, `starttls:`; look for lines containing **Unable**, **failed**, **Error**, **Authentication**, **535**, etc.

## 7. Common mistakes and fixes

| Issue | Fix |
|-------|-----|
| Missing setFrom() | Always call `$email->setFrom($address, $name)` before send. |
| Invalid SMTP config | Set protocol, host, user, pass, port, crypto in `.env`. |
| Port 25 blocked | Use 587 (tls) or 2525 (SendGrid). |
| Gmail “Less secure app” | Use an App Password, not the main password. |
| Charset / broken characters | Config has `charset = 'UTF-8'`; send UTF-8 body. |
| Seeing “250-SMTPUTF8” as error | Upgrade to the fixed error extraction (skips `^\d{3}[\s-]` lines). |

## 8. Summary

- **250-SMTPUTF8** is a normal SMTP line; the app was misusing it as the error message. Error extraction is now fixed.
- **Email.php** is set up for SMTP, UTF-8, and Gmail/SendGrid.
- **send_mail()** validates `setFrom`, sets HTML and UTF-8, and logs full `printDebugger()` output on failure.
- Use **.env** for SMTP and check **writable/logs** when debugging.
