SMTP
CodeIgniter SMTP fails silently when protocol is left at mail. Set it to smtp, match crypto to port, use correct CI3/CI4 keys, and call print_debugger().
Updated Jul 1, 2026
The short answer
"CodeIgniter SMTP mail not working" is not an SMTP reply code; it is a catch-all for the Email class failing silently or send() returning false. The usual cause is leaving protocol at its default ('mail') so SMTP is never used, plus a wrong host, port, or crypto pairing, wrong CI3-versus-CI4 config keys, or bad auth. Fix it by setting protocol to 'smtp', using the correct snake_case keys in CI3, matching the crypto setting to the port, using a Gmail App Password, and calling print_debugger() after send(false) to read the real error.
No. There is no SMTP reply code or enhanced status code by this name. It's a generic label for any situation where CodeIgniter's Email class fails to deliver over SMTP — typically $email->send() returning false, a connection timeout, or mail that appears "sent" but is actually being handed to PHP's local mail() function instead of your SMTP server. Because the symptom is generic, the first job is to surface the real underlying error (which often is a standard SMTP code like 535 5.7.8 auth failure or a socket-level connection refusal).
CodeIgniter clears the email data after a normal send(), so you must pass false to keep it, then print the debugger:
if (! $this->email->send(false)) { // CI3: send(FALSE) — keep dataecho $this->email->print_debugger(['headers', 'subject', 'body']);}// CodeIgniter 4:// if (! $email->send(false)) { echo $email->printDebugger(['headers']); }
This prints the SMTP conversation and the server's reply (e.g. 535 5.7.8 Username and Password not accepted, Failed to connect to server, STARTTLS failed). Diagnose from that reply rather than guessing. (CodeIgniter Email Class docs.)
protocol left at the default. CodeIgniter's Email class defaults protocol to mail (the PHP mail() function) — not smtp. If you never set the protocol to smtp, your SMTP host/user/pass are ignored and PHP tries the local mailer, which silently does nothing on most servers. This is the single most common cause.protocol, smtp_host, smtp_user, smtp_pass, smtp_port, smtp_crypto, smtp_timeout, mailtype). CI4 uses camelCase/property-style names (protocol, SMTPHost, SMTPUser, SMTPPass, SMTPPort, SMTPCrypto, SMTPTimeout, mailType). Don't mix them.SMTPCrypto/smtp_crypto to an empty string ('') for port 465, since STARTTLS is not needed), and port 587 uses STARTTLS (use tls). Pairing 465 with 'tls', or 587 with an empty/implicit-SSL setting, causes a handshake/STARTTLS failure. Both 465 and 587 are valid and current — neither is deprecated.535 5.7.8). Wrong username/password, or — for Gmail/Google Workspace — using your normal account password. Google removed "Less Secure Apps" (personal accounts on May 30, 2022; Workspace phased out after), so you must use an App Password (requires 2-Step Verification) or OAuth 2.0. Do not look for a "less secure apps" toggle — that setting no longer exists.telnet smtp.host 587 from the server and ask the host to open the port or use an API-based sender.newline/crlf must be the real escape sequence "\r\n" to comply with RFC 5322. A literal "/r/n" (forward slashes, as in many copy-pasted snippets) produces malformed headers and rejected or garbled mail. Note that escape sequences are interpreted in double quotes but treated literally in single quotes — a single-quoted '\r\n' is not a real CRLF.In CI3, use the snake_case keys, set protocol to smtp, match the crypto to the port, use real \r\n, and use an App Password for Gmail:
$config = ['protocol' => 'smtp', // REQUIRED — without this, SMTP is never used'smtp_host' => 'smtp.gmail.com','smtp_user' => 'you@gmail.com','smtp_pass' => 'your-16-char-app-password', // NOT your login password'smtp_port' => 587, // 587 -> STARTTLS'smtp_crypto' => 'tls', // use '' (empty string) for port 465 (implicit TLS)'smtp_timeout' => 30,'mailtype' => 'html','charset' => 'utf-8','newline' => "\r\n", // real CRLF, double quotes — RFC 5322'crlf' => "\r\n",];$this->load->library('email');$this->email->initialize($config);$this->email->from('you@gmail.com', 'Your App');$this->email->to('recipient@example.com');$this->email->subject('Test');$this->email->message('<p>Hello from CodeIgniter</p>');if (! $this->email->send(false)) {log_message('error', $this->email->print_debugger(['headers']));}
Note: in CI3 the keys are lowercase snake_case (smtp_host, smtp_crypto, smtp_port, ...). Using the CI4-style SMTPHost/SMTPCrypto names here is a common mistake — CI3 silently ignores unrecognized keys, so SMTP never gets configured and the send falls back to the default mail protocol.
In CI4, configure app/Config/Email.php (or pass an array to \Config\Services::email()), then $email->send() / $email->printDebugger(). The concepts (protocol => 'smtp', host, port/crypto pairing, App Password) are the same, but the key names differ from CI3: CI4 uses SMTPHost, SMTPUser, SMTPPass, SMTPPort, SMTPCrypto, SMTPTimeout, and mailType. Don't copy CI3 snake_case keys into a CI4 config or vice-versa.
If the debugger shows a clean SMTP 250 accept but mail never arrives, the problem has moved downstream to deliverability — SPF/DKIM/DMARC alignment, the sending IP's reputation, or spam filtering — not CodeIgniter. Sending through a dedicated provider (or a notifications API such as Courier) over an authenticated API instead of raw SMTP sidesteps host port-blocking and gives you delivery logs to diagnose the rest.
References
FAQ
Most often because protocol was left at its default ('mail'/'sendmail') instead of 'smtp', so CodeIgniter handed the message to PHP's local mailer, which silently discards it on servers without a configured MTA. Set protocol => 'smtp' and re-test with send(false) + printDebugger(). If SMTP returns 250 but mail still doesn't arrive, the issue is deliverability (SPF/DKIM/DMARC or spam filtering), not CodeIgniter.
One API, every provider
Courier connects to your email, SMS, and push providers, handles retries and failover, and surfaces delivery errors in plain language.
Reply-code definitions per RFC 8314 §3.3 (implicit TLS / port 465 vs 587); RFC 5322 (CRLF line endings). Last reviewed Jul 1, 2026. Courier is not affiliated with third-party providers; error behavior may vary by implementation.
© 2026 Courier. All rights reserved.