December 5, 2025
This is an example docker-compose.yml running Reacher service on DigitalOcean to verify email deliverability. Port 22 muse be open
services:
rabbitmq:
image: rabbitmq:4.0-management
environment:
RABBITMQ_DEFAULT_USER: reacher
RABBITMQ_DEFAULT_PASS: reacher
ports:
- "5672:5672"
- "15672:15672"
restart: unless-stopped
networks:
- dokploy-network
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "ping"]
interval: 5s
timeout: 3s
retries: 5
worker:
image: reacherhq/backend:v0.11.5
ports:
- "8080:8080"
depends_on:
rabbitmq:
condition: service_healthy
environment:
RCH__BACKEND_NAME: worker
RCH__HTTP_PORT: ${RCH__HTTP_PORT}
RCH__HELLO_NAME: ${RCH__HELLO_NAME}
RCH__FROM_EMAIL: ${RCH__FROM_EMAIL}
RCH__HEADER_SECRET: ${RCH__HEADER_SECRET}
RUST_LOG: reacher=info
RCH__WORKER__ENABLE: true
RCH__WORKER__RABBITMQ__URL: amqp://reacher:reacher@rabbitmq:5672
RCH__STORAGE__POSTGRES__DB_URL: ${RCH__DB_URL}
RCH__WORKER__THROTTLE__MAX_REQUESTS_PER_DAY: ${RCH__WORKER__THROTTLE__MAX_REQUESTS_PER_DAY}
restart: unless-stopped
networks:
- dokploy-network
networks:
dokploy-network:
external: true
Env:
RCH__HTTP_PORT=8080
RCH__HELLO_NAME=verify.example.com
RCH__FROM_EMAIL=hello@verify.example.com
RCH__HEADER_SECRET=LONGSTRINGOFWHATEVR
RCH__WORKER__THROTTLE__MAX_REQUESTS_PER_DAY=1000000
RCH__DB_URL=postgresql://yourdb
Then to verify:
type EmailVerificationResponse = {
input: string,
is_reachable: 'safe' | 'risky' | 'unknown' | 'invalid',
misc: MiscInfo,
mx: MxInfo,
smtp: SmtpInfo,
syntax: SyntaxInfo,
};
const ACCEPTED_STATUSES = ['safe', 'risky'];
const TIMEOUT = 1000 * 5;
export const validateEmail = async (email: string) => {
if (!email.includes('@')) return false;
try {
const response = await request<EmailVerificationResponse>({
url: 'https://verify.example.com/v0/check_email',
method: 'post',
data: { to_email: email },
headers: { 'x-reacher-secret': process.env.REACHER_TOKEN! },
timeout: TIMEOUT,
});
return ACCEPTED_STATUSES.includes(response.is_reachable);
} catch {
return false;
}
};