| name | sub2api-resend-mail |
| description | Configure Sub2API registration email verification and transactional email delivery through Resend. Use when Codex needs to enable Sub2API email verification, set SMTP/database settings, troubleshoot blocked outbound SMTP ports, or install a local SMTP-to-Resend API relay for a Docker-based Sub2API deployment. |
Sub2API Resend Mail
Use this skill to configure a Sub2API deployment so registration requires an email verification code and emails are sent through Resend.
Core Workflow
-
Connect to the server and identify the real Sub2API runtime.
- Check
docker ps, systemctl status sub2api, listening ports, and the project directory.
- Do not assume
/opt/sub2api/deploy/sub2api.service is active; many deployments run weishaw/sub2api:latest in Docker.
-
Confirm the existing registration/email flow.
- Sub2API already supports email verification through:
POST /api/v1/auth/send-verify-code
POST /api/v1/auth/register
verify_code in the registration payload
- Backend settings are stored in the
settings table.
-
Configure built-in SMTP first when outbound SMTP works.
- Resend SMTP settings:
- host:
smtp.resend.com
- username:
resend
- password: Resend API key
- from: a verified sender such as
noreply@api.example.com
- port:
465 with implicit TLS, or 587 with STARTTLS
- Test from the server before relying on it:
timeout 10 bash -lc 'cat < /dev/null > /dev/tcp/smtp.resend.com/587'
timeout 10 bash -lc 'cat < /dev/null > /dev/tcp/smtp.resend.com/465'
-
If outbound SMTP is blocked, install a local relay.
- Sub2API's Go SMTP sender requires SMTP AUTH.
- If the relay is accessed as
127.0.0.1, Go allows auth over a local plaintext SMTP connection.
- Run the relay with
--network container:sub2api so Sub2API reaches it at 127.0.0.1:2525.
- The relay accepts local SMTP and sends through
https://api.resend.com/emails.
-
Enable Sub2API email verification in the database and restart Sub2API.
-
Verify by calling:
$body = @{ email = 'target@example.com' } | ConvertTo-Json
Invoke-RestMethod -Method Post `
-Uri 'http://SERVER:PORT/api/v1/auth/send-verify-code' `
-ContentType 'application/json' `
-Body $body
Success from the API only means the task was queued. Confirm the final result in logs:
docker logs --since 60s sub2api 2>&1 | grep -E 'EmailQueue|verify code|smtp|send-verify-code'
Look for:
[EmailQueue] Worker N sent verify code to user@example.com
Database Settings
For direct Resend SMTP, set values like:
INSERT INTO settings (key, value, updated_at) VALUES
('smtp_host', 'smtp.resend.com', NOW()),
('smtp_port', '465', NOW()),
('smtp_username', 'resend', NOW()),
('smtp_password', '<RESEND_API_KEY>', NOW()),
('smtp_from', 'noreply@api.example.com', NOW()),
('smtp_from_name', 'Example', NOW()),
('smtp_use_tls', 'true', NOW()),
('email_verify_enabled', 'true', NOW())
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = NOW();
For the local relay pattern, set:
INSERT INTO settings (key, value, updated_at) VALUES
('smtp_host', '127.0.0.1', NOW()),
('smtp_port', '2525', NOW()),
('smtp_username', 'resend', NOW()),
('smtp_password', 'unused', NOW()),
('smtp_from', 'noreply@api.example.com', NOW()),
('smtp_from_name', 'Example', NOW()),
('smtp_use_tls', 'false', NOW()),
('email_verify_enabled', 'true', NOW())
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = NOW();
Run SQL through the Postgres container to avoid local quoting issues:
$sql = @'
select key, case when key='smtp_password' then '[redacted]' else value end
from settings
where key in ('email_verify_enabled','registration_enabled','smtp_host','smtp_port','smtp_username','smtp_password','smtp_from','smtp_from_name','smtp_use_tls')
order by key;
'@
$sql | ssh root@SERVER "docker exec -i sub2api-postgres psql -U sub2api -d sub2api -At"
Local Relay
Use references/resend-smtp-relay.md when SMTP ports are blocked or Resend SMTP times out.
Keep secrets out of the skill files. Use placeholders such as <RESEND_API_KEY> and pass real values through environment variables, database settings, or a secret manager.
Troubleshooting
404 page not found on /api/auth/send-verify-code: use /api/v1/auth/send-verify-code.
- API returns success but no email arrives: check the async queue logs, not only the HTTP response.
tls dial ...:465 i/o timeout or port 587 timeout: use the local relay pattern.
smtp auth: unencrypted connection: either use STARTTLS or make the SMTP server local to Sub2API at 127.0.0.1.
x509: certificate signed by unknown authority: do not advertise STARTTLS from a self-signed relay unless Sub2API trusts that CA.
- After changing settings in the database, restart the
sub2api container so cached settings reload.