Calendar invite delivered externally, missing internally#
Stack: cPanel + Exim (MTA) + Dovecot (IMAP/POP3) + Roundcube or Horde (Webmail) Calendar client: Thunderbird (with CalDAV configured) Server type: Shared hosting or self-managed VPS with cPanel/WHM
Executed test flow:
1. cPanel → create sender@mydomain.com + enable CalDAV calendar
2. Thunderbird → configure email account + connect calendar via CalDAV
3. Thunderbird Calendar → create test event
4. Add attendees:
- recipient@mydomain.com ← INTERNAL (same server)
- user@otherdomain.com ← EXTERNAL
5. Send invites
Observed result:
| Recipient | Received email? | Received invite? |
|---|---|---|
user@domain.com | ✅ In inbox, with .ics attachment | ✅ |
user@domain.com | ❌ No email in inbox | ❓ Unknown |
Layer 1 - delivery tracking: did Exim even log it?#
Checking via cPanel track delivery#
The first forensic action is to verify whether Exim generated a delivery entry for the internal recipient at all. In cPanel:
WHM / cPanel → Email → Track Delivery
→ Filter by: recipient@mydomain.com
→ Time range: covering the moment the invite was sent
Interpreting possible statuses:
| Track Delivery Status | Meaning |
|---|---|
Success → delivered | Email reached the Dovecot mailbox - problem is client not syncing |
Deferred → timeout/retry | Exim is trying to deliver but encountered a delay (check queue) |
Failed → bounce | Exim refused with an error (check bounce code) |
| Absent from list | Exim never generated an envelope for this recipient - invite was intercepted before MTA |
Checking the Exim log directly via SSH:
# Search for the internal recipient in Exim mainlog
grep "recipient@mydomain.com" /var/log/exim_mainlog | tail -30
# Search for loop or unroutable errors recently
grep -E "loop detected|unroutable|lost connection" /var/log/exim_mainlog | tail -20
# View current Exim queue (pending messages)
exim -bp | head -30
Output indicating absence of envelope for the internal recipient:
# → No lines found for recipient@mydomain.com
# This confirms: Exim never processed any envelope for this address
# The invite was intercepted BEFORE reaching the MTA
Layer 2 - the calendar intercept "feature" for local recipients#
This is the core behavior causing the confusion. On cPanel servers with Roundcube or Horde, there is a local recipient calendar intercept mechanism:
Thunderbird sends invite via CalDAV → cPanel CalDAV server
│
▼
Server receives the event with attendee list
│
▼
For each attendee:
├── Is it EXTERNAL (different domain)?
│ └── → Generates Exim envelope → sends email with .ics attachment
│ Recipient gets it in their inbox ← expected behavior
│
└── Is it INTERNAL (same server)?
└── → INTERCEPTS the invite
→ Injects the event directly into recipient's calendar via backend
→ Event status: "Tentative" or "Pending"
→ No email is sent to the IMAP inbox
Why does this exist? It is a performance and anti-spam optimization: for accounts on the same server, there is no need to generate internal SMTP traffic - the server can write the event directly to the recipient's CalDAV/vCard storage. The intention is good; the user experience is confusing.
Where to find the intercepted event:
Thunderbird → Calendar tab
→ Connect CalDAV calendar of recipient@mydomain.com
→ Check for events with "Tentative" status or without confirmation
Or directly via Roundcube/Horde:
Roundcube → Login as recipient@mydomain.com → Calendar
→ Check "Pending" tab or events marked as tentative
Layer 3 - email routing: local mail exchanger#
A variable that can amplify the problem or cause different behavior is the email routing configuration for the domain in cPanel. If the domain is not configured as Local Mail Exchanger, Exim may try to route to an external server (such as an antispam gateway) even for local accounts.
Checking and correcting:
cPanel → Email → Email Routing
→ Select the domain
→ Check current configuration
Possible states:
| Configuration | Behavior | When to use |
|---|---|---|
| Automatically Detect | cPanel decides based on MX records | ❌ Problematic if there's an external antispam in MX |
| Local Mail Exchanger | All email destined for this domain is delivered locally, without consulting MX | ✅ Correct for locally hosted domains |
| Backup Mail Exchanger | Accepts email but may forward to another server | For backup MX servers |
| Remote Mail Exchanger | Forwards all email to external server | For domains with Google Workspace, Microsoft 365, etc. |
Setting via WHM CLI:
# Check current routing configuration
whmapi1 get_email_routing | grep -A 5 "mydomain.com"
# Force Local Mail Exchanger via API
whmapi1 set_email_routing domain=mydomain.com mailrouting=local
Verifying domain MX records (to understand what "Automatic" is interpreting):
# Check domain MX records
dig MX mydomain.com
# If MX points to an external antispam (e.g., SpamExperts), cPanel in
# Automatic mode will consider it "Remote" and route externally
# → Solution: change to "Local" explicitly
Layer 4 - Dovecot session validation: doveadm who#
To ensure that client-server communication is healthy and that the IMAP sessions of the user not receiving email are intact (ruling out connection problems as a collateral cause), the audit is performed via doveadm:
# List ALL active IMAP/POP3 sessions at this moment
doveadm who
# Expected output (example):
# username # proto (pids) (ips)
# sender@my... 1 imap (12345) (192.168.1.10)
# recipient@my... 1 imap (12346) (192.168.1.11)
Filter specifically by the problematic user:
doveadm who -u recipient@mydomain.com
# Expected output if user is connected:
# username # proto (pids) (ips)
# recipient@mydomain.com 1 imap (12346) (192.168.1.11)
# If no output appears → user is not currently connected via IMAP
# This is normal and does not indicate a problem
Detailed view with one connection per line:
doveadm who -1
# Detailed format output:
# recipient@mydomain.com imap 12346 192.168.1.11
Checking the user's mailbox directly:
# View messages delivered to the mailbox (confirm if any email arrived)
doveadm mailbox status -u recipient@mydomain.com messages INBOX
# List the last 10 messages in the INBOX
doveadm fetch -u recipient@mydomain.com 'date subject from' mailbox INBOX all | tail -30
Layer 5 - TCP connectivity validation with ss and netstat#
To see IMAP traffic at the TCP socket level (useful for confirming the client is actively connected to Dovecot):
# Using ss (modern netstat replacement - preferred on AlmaLinux/CloudLinux 8+)
ss -tnp | grep dovecot
# Expected output:
# ESTAB 0 0 192.168.1.11:54321 10.0.0.1:993 users:(("dovecot",pid=12346,...))
# ESTAB state = active established TCP connection on port 993 (IMAP over SSL)
# Using netstat (available on older systems)
netstat -anp | grep dovecot | grep ESTABLISHED
# Filtering by specific client IP
ss -tnp | grep dovecot | grep "192.168.1.11"
Dovecot port reference:
| Port | Protocol | Description |
|---|---|---|
| 143 | IMAP | IMAP without SSL (STARTTLS available) |
| 993 | IMAPS | IMAP with SSL/TLS |
| 110 | POP3 | POP3 without SSL |
| 995 | POP3S | POP3 with SSL/TLS |
Differential diagnosis: webmail vs. thunderbird test#
The definitive test to isolate whether the problem is in the client or the server:
TEST A: Send invite via THUNDERBIRD to recipient@mydomain.com
→ If invite doesn't appear in email but appears in recipient's CalDAV calendar
→ Confirms: local calendar intercept (normal server behavior)
TEST B: Send invite via ROUNDCUBE/HORDE (webmail) to recipient@mydomain.com
→ If behavior is identical → confirms it's server behavior
→ If email arrives via webmail → identity/configuration problem in Thunderbird
TEST C: Check sender identity in Thunderbird
→ Thunderbird → Tools → Account Settings → Identities
→ Ensure email = sender@mydomain.com (no alternative identity generating
confusion in the invite's From/Reply-To headers)
Summary: decision tree#
Internal invite not arriving in inbox
│
▼
cPanel Track Delivery → entry exists for internal recipient?
│
NO ─┼──→ Exim never generated envelope
→ Local calendar intercept (expected behavior)
→ Check recipient's CalDAV calendar
→ Verify Email Routing = "Local Mail Exchanger"
│
YES ─┼──→ Exim generated envelope - what is the status?
├── Success → Email in Dovecot mailbox, client not syncing
│ → doveadm fetch + check IMAP config in Thunderbird
├── Deferred → Queue retrying, wait or force retry
│ → exim -M <message-id> to force immediate delivery
└── Failed → Bounce with error code
→ Analyze SMTP error code in Exim log
Was this article helpful?
Leave a quick reaction to help prioritize future technical guides:
This post is licensed under CC BY-NC.



Comments
Join the discussion below.
0 comments