monsterb

Testing Odoo outgoing e-mail without a real mail server

Odoo 19 · Python 3 · checked on macOS

Settings > Technical > Outgoing Mail Servers has a Test Connection button. When it answers "No response received. Check server address and port number." after about 25 seconds, the credentials were never tried: the TCP connection did not complete.

1. Is it the port or the account?

Probe the port from the machine that runs Odoo, and compare with a host you know works. A timeout and an immediate refusal mean different things.

import socket
for host, port in [("smtp.example.org", 25), ("smtp.gmail.com", 25), ("smtp.gmail.com", 587)]:
    s = socket.socket(); s.settimeout(8)
    try:
        s.connect((host, port)); print(host, port, "open", s.recv(80)[:60])
    except Exception as e:
        print(host, port, type(e).__name__)
    finally:
        s.close()
ResultMeaning
TimeoutError on 25, but 587 connectsYour network drops outbound port 25. Many ISPs do. Not an Odoo or credentials problem.
ConnectionRefusedError (fast, ~0.2 s)The host answered and nothing listens on that port. Use the port the provider documents.
Connects, banner shown, Odoo still failsNow check encryption (none / STARTTLS / SSL) and the login.

2. Capture mail locally instead

To check what a template looks like you do not need delivery at all. Run a sink that accepts any message and writes it to disk:

python3 smtp_sink.py 1025 mail-sink

Source: smtp_sink.py. It uses only the standard library, handles the dot-stuffing of the SMTP DATA command, and ignores a client that hangs up early (a port probe, for example).

Then edit the outgoing mail server in Odoo:

SMTP Server127.0.0.1
SMTP Port1025
Connection SecurityNone
Authenticationnone needed (leave user and password empty)
From Filterempty

Each message lands as mail-sink/0001-recipient.eml. Open it in a mail client, or read the HTML part in a browser.

3. "Sent" in the UI is not "delivered"

An action that queues mail (mail.mail with a cron) returns success at once. The real result is the state and failure_reason of the mail.mail record and the Odoo log. A custom log row that says sent may only mean "queued". When a button seems to do nothing, look there first:

select id, state, left(failure_reason, 120) from mail_mail order by id desc limit 5;

One failure I hit this way came from the provider, not from Odoo: SMTPDataError (500, ... Failed to send mail No balance). A temporary mailbox service had a send quota, and a script using smtplib directly got the same error, which ruled Odoo out.

4. A real server for staging: Lark Mail

If a staging environment needs real delivery, Lark Mail can be used as an SMTP server for an address on a domain you control. From Lark's documentation:

Set the Odoo From Filter and the mail.default.from system parameter to that same address, so the sender matches the login.