# DEPLOYDOCS

## Deployed

- frontend url: `https://validator.pinmarko.com`
- frontend path: `/home/zipperic48/validator.pinmarko.com`
- backend url: `https://api-validator.pinmarko.com`
- backend path: `/home/zipperic48/api-validator.pinmarko.com`
- backend app root: `/home/zipperic48/api-validator.pinmarko.com`
- backend version: `1.0.142`
- remote override env file: `/home/zipperic48/api-validator.pinmarko.com/server/.env`

## Database

- engine: `mysql`
- host: `127.0.0.1`
- port: `3306`
- database: `zipperic48_validator`
- username: `zipperic48_validusr`
- password: `YWJHuBXtblQiOyz0XO1U`

## cPanel

- url: `zipperi.com`
- username: `zipperic48`
- api: `TE6TV2KDXDF1TZ6RXW568W3T4LNHSUTD`

## Backend Runtime

- startup file: `server.cjs`
- app restart: `CloudLinux Node.js App restart`
- passenger node: `/home/zipperic48/nodevenv/api-validator.pinmarko.com/24/bin/node`
- validation mode: `full`
- smtp connection mode: `proxy_pool`
- smtp mail-from domain: `api-validator.pinmarko.com`
- dns resolution fallback: `local resolver first; dns.google DoH fallback for MX/TXT when local DNS fails or returns unusable MX answers`
- google mailbox validation: `SMTP first; Google account signal fallback only when configured and SMTP is inconclusive`
- google lightweight signal flow: `tries WebLite sign-in path before falling back; generic /v3/signin/rejected stays inconclusive`
- google consumer mailbox handling: `gmail.com/googlemail.com now always try Google account signal before SMTP, and retry signal when SMTP is ambiguous or catch-all-like`
- microsoft provider-signal proxy: `lightningproxies.net` via `PROVIDER_SIGNAL_DIRECT_PROXY_URL` (shared direct proxy, URL syntax corrected in `1.0.126`)
- microsoft provider-signal retry attempts: `2`
- proxy source: `ProxyScrape text feed + Geonode API JSON feed by default; override with PROXY_SOURCE_URLS / PROXY_SOURCE_URL`
- enterprise proxy sources: `ProxyScrape text feed + Geonode API JSON feed by default; override with ENTERPRISE_PROXY_SOURCE_URLS if needed`
- proxy refresh: `every 30 minutes`
- outlook proxy refresh: `every 40 minutes`
- standard proxy preflight: `banner + EHLO/HELO + MAIL FROM against Gmail before saving; weeds out proxies that connect then die during real SMTP`
- microsoft smtp fallback proxy pool: `standard smtp proxy pool`
- outlook proxy preflight: `not used for Microsoft mailbox validation; Microsoft uses provider signal through proxy.market first, then standard smtp proxy pool fallback`
- google provider-signal proxy: `lightningproxies.net` via `PROVIDER_SIGNAL_DIRECT_PROXY_URL` and `GOOGLE_ACCOUNT_SIGNAL_PROXY_URL`
- google provider-signal proxy order: `direct proxy first, then standard proxy pool fallback when signal is enabled`
- google workspace signal mode: `smtp first; Google account signal fallback via GOOGLE_WORKSPACE_ACCOUNT_SIGNAL_MODE=fallback`
- google account signal bandwidth controls: `retry attempts 1; 24h in-memory cache for conclusive results; 5m cache for inconclusive results; curl uses compression; modern Google JS-only sign-in is fast-skipped before downloading the full page`
- google account signal current status: `legacy form parser only; modern Google InteractiveLogin returns inconclusive and falls back to SMTP`
- google account signal run logs: `validation run logs now record google_signal start, result, and SMTP fallback transitions`
- google catch-all policy: `do not mark Google Workspace accepted RCPT as catch-all from fake-address probes; hard 550/not-found remains invalid`
- yahoo account signal mode: `signal first via YAHOO_ACCOUNT_SIGNAL_MODE=first for yahoo.com and ymail.com`
- yahoo account signal transport order: `direct connection first; proxy pool disabled by default via YAHOO_ACCOUNT_SIGNAL_USE_PROXY_POOL=false; rotating direct proxy disabled by default because Yahoo crumb/session validation breaks across rotating exits`
- yahoo account signal timeout: `15s default via YAHOO_ACCOUNT_SIGNAL_TIMEOUT_MS`
- yahoo account signal verdicts: `password/full-name/verification challenges => exists; Sorry, we don't recognize this email or deactivated-account fail pages => not_found; INVALID_IDENTIFIER / INVALID_AS / rate limits => inconclusive`
- yahoo smtp fallback: `used only when Yahoo account signal is inconclusive`
- yahoo accept-all policy: `if Yahoo account signal stays inconclusive, SMTP accept-all behavior is downgraded to unknown instead of catch-all`
- proxy check timeout: `30 seconds per proxy`
- standard proxy refresh concurrency: `40`
- proxy active ttl: `60 minutes`
- proxy pool target: `100`
- proxy replenish threshold: `25 active proxies`
- max validations per run: `unlimited`
- max validations per proxy: `100`
- validation timeout: `90 seconds default for full mailbox validation`
- bulk validation concurrency: `10 default; cap 12 via BULK_VALIDATION_MAX_CONCURRENCY`
- bulk validation timeout: `45 seconds per email via BULK_EMAIL_VALIDATION_TIMEOUT_MS`
- bulk validation retries: `2 proxy attempts; first attempt 15 seconds; min useful attempt 8 seconds`
- bulk email detail logs: `disabled by default for speed; set BULK_EMAIL_DETAIL_LOGS=true only when debugging`
- bulk progress flush: `every 10 rows or 2 seconds`
- bulk proxy wait: `wait up to 5 minutes for at least 1 active standard proxy before continuing`
- validation timeout proxy retries: `3 attempts inside 90 seconds, first attempt defaults to 25 seconds`
- validation min attempt timeout: `12 seconds to avoid late retry collapse into immediate unknown`
- timeout proxy handling: `aborted/timed-out SMTP proxy attempts are marked failed so slow proxies leave the active pool`
- generic catch-all confirmation: `mixed fake-address results become unknown instead of catch-all; generic providers require all confirmation probes accepted before catch-all`
- enterprise ambiguous-recipient probe: `for mimecast/other hybrid-style providers, if target RCPT is temporary/ambiguous but same-session fake recipient gets hard reject, treat mailbox as likely existing; if fake recipient is accepted, treat as catch-all`
- enterprise negative-probe fallback: `if final enterprise/Mimecast result is still ambiguous (like 451), run one fake-recipient domain probe and infer valid vs catch-all from that follow-up result`
- negative-probe safety: `fake-recipient follow-up only counts as mailbox-missing when the server says invalid/user-unknown style text; proxy/blocklist 550s stay inconclusive`
- bulk hybrid fan-out tuning: `for bulk scope on generic/other hybrid providers, each attempt now uses 1 MX and at most 1 proxy fallback so retries rotate faster instead of timing out on wide fan-out`
- enterprise smtp preferred proxy: `Mimecast hybrid SMTP now tries the paid direct proxy from PROVIDER_SIGNAL_DIRECT_PROXY_URL/SMTP_ENTERPRISE_DIRECT_PROXY_URL before the free proxy pool; generic other hybrid relays stay on direct + standard proxy fallback`
- enterprise screened proxy pool: `Mimecast now uses dedicated enterprise proxy pool after the paid preferred proxy; free proxies only enter this pool if fake-recipient preflight gets a hard mailbox reject on known Mimecast domains`
- enterprise standard fallback: `if the dedicated enterprise pool is empty, live Mimecast validations can now fall back to diversified standard SMTP proxies after the paid preferred proxy instead of stopping with no proxy paths`
- enterprise proxy min-ready behavior: `enterprise candidate fetch now honors minReady=0 for hybrid flows, so Mimecast can immediately continue into standard fallback while the dedicated enterprise pool is still rebuilding`
- enterprise proxy preflight domains: `aetna.com,pinnacleadvisory.com,ppdi.com,gastrocenter.org` via `ENTERPRISE_PROXY_PREFLIGHT_DOMAINS`
- enterprise proxy pool target: `10` via `ENTERPRISE_PROXY_POOL_TARGET_SIZE`
- enterprise proxy pool target: `15` via remote override `server/.env`
- enterprise proxy refresh scan cap: `1500` candidates via remote override `server/.env`
- enterprise proxy refresh concurrency: `60` via remote override `server/.env`
- enterprise proxy refresh: `every 40 minutes by default; also maintained every minute when active count drops below target`
- bulk unknown delayed recheck: `retryable bulk unknowns now get 1 delayed second-pass validation (15s wait by default) before final CSV export`
- bulk unknown recheck scope: `delayed bulk unknown rechecks now run with wider single-style SMTP retry budget and timeout via BULK_UNKNOWN_RECHECK_TIMEOUT_MS instead of repeating the first-pass bulk cap`
- bulk unknown recheck timing: `delayed rechecks now favor a larger first attempt and default to 2 outer timeout retries, so timeout-only generic domains spend less budget on tiny tail retries`
- bulk recheck generic hybrid tuning: `bulk_recheck scope now loosens generic hybrid fan-out to up to 2 MX / 2 connection paths, instead of first-pass 1x1 throttling`
- mimecast attempt budgeting: `each outer validation attempt now focuses on 1 Mimecast MX and at most 1 proxy fallback; later timeout retries rotate MX/proxy instead of burning one call across too many paths`
- bulk scope propagation: `bulk/bulk_recheck scope now flows into mailbox strategy so generic hybrid fan-out tuning applies on first bulk pass, while delayed recheck can intentionally use broader scope`
- timeout retry signal source: `unknown-result retries now inspect SMTP raw responses too, so policy/blocklist proxy failures can trigger another MX/proxy attempt`
- enterprise transient retry policy: `Mimecast/enterprise 451 temporary/deferred responses now count as retryable unknowns, so outer timeout retries can rotate MX/proxy instead of stopping after the first ambiguous result`
- enterprise negative-probe transport: `final ambiguous Mimecast fallback probe can now use direct plus the paid preferred enterprise proxy, while still skipping the free proxy pool to avoid unsafe catch-all inferences`
- enterprise HELO override: `Mimecast/other enterprise SMTP can now use SMTP_ENTERPRISE_HELO_HOST / SMTP_FCRDNS_HELO_HOST for EHLO/HELO without changing Google/Yahoo provider-specific identities`
- enterprise HELO host: `lv-shared04.cpanelplatform.com` via `SMTP_ENTERPRISE_HELO_HOST` and `SMTP_FCRDNS_HELO_HOST`
- smtp run telemetry: `SMTP result payloads now include heloHost and acceptedMailFrom so live logs show which SMTP identity actually reached RCPT stage`
- smtp proxy diversity: `each validation now prefers unique proxy networks/hosts per attempt so one dead multi-port proxy farm does not consume the whole attempt budget`
- smtp abort handling: `SOCKS proxy connects now honor abort signals, reducing timed-out background attempts that used to keep burning proxy budget after the outer validation moved on`
- smtp socks crash guard: `timed-out SOCKS clients keep a passive late-error listener during teardown so Passenger does not restart on delayed library error events`
- proxy auth/header parity: `HTTP proxy CONNECT now only sends Proxy-Authorization when credentials actually exist, matching preflight behavior and avoiding blank-auth 407 failures on anonymous proxies`
- reputation-block proxy retirement: `Mimecast CSS/XBL/Invaluement/ivmSIP blocks are now treated as infrastructure blocks, so those proxies are not counted as successful mailbox probes and are retired faster from active pools`
- preferred-proxy-only fallback: `final Mimecast enterprise negative probe can force direct + preferred paid proxy only, skipping known-bad free proxies during that safety check`
- proxy-only smtp mode: `set SMTP_PROXY_ONLY=true to disable all direct SMTP connection attempts; hybrid/direct mailbox validation then uses proxy paths only, and Yahoo account-signal direct web requests are disabled too`
- enterprise preferred proxy cooldown: `30 seconds via ENTERPRISE_PREFERRED_PROXY_COOLDOWN_MS=30000, so a timed-out preferred Mimecast proxy is retried quickly instead of being skipped for a long window`
- proxy-only Mimecast connection attempts: `4 standard-proxy paths max via SMTP_PROXY_ONLY_MIMECAST_MAX_CONNECTION_ATTEMPTS=4`
- preferred enterprise proxy timeout: `2 seconds via remote override PREFERRED_ENTERPRISE_PROXY_TIMEOUT_MS=2000`
- enterprise preferred proxy cooldown: `10 minutes via remote override ENTERPRISE_PREFERRED_PROXY_COOLDOWN_MS=600000`
- provider smtp retry policy: `provider-specific retryAttempts are now honored for generic/provider-strategy SMTP flows instead of always forcing the global retry count`
- guarded apify fallback: `backend can now use the Apify actor only as a guarded stronger-verdict fallback for enterprise single-email unknowns, and bulk runs can batch unresolved enterprise unknowns through Apify once at the end; Apify invalid is accepted only on hard reject evidence`
- apify actor semantics: `actor no longer falls through timeout/inconclusive SMTP into weak invalid verdicts from ping-email/email-verify by default; Mimecast/pphosted detection added; actor SMTP identity now uses validator.pinmarko.com / SMTP_MAIL_FROM_DOMAIN instead of protonmail.com`
- apify validator runtime: `actor PdgDfNOAmNxDlo501 build 0.1.23; direct mode; max retries 0; max concurrency 5; timeout 12s; wait-for-finish 300s`
- timeout result preservation: `if SMTP verification finished with a concrete partial result just before the outer attempt budget expired, the backend now keeps that richer result instead of overwriting it with a generic timed-out unknown`
- delayed timeout preservation: `after an outer timeout fires, the backend now waits a short grace window for a just-finishing SMTP result so gateway verdicts that arrive milliseconds late still replace a generic timeout`
- relay/policy reject handling: `responses like SPF fail, not authorized, not relaying, and sender verify failed are treated as gateway/policy failures, not mailbox-missing verdicts`
- blocked proxy retirement: `free SMTP proxies that hit not-allowed / host-network-not-allowed gateway blocks are now retired from the active pool faster instead of being reused`
- generic/enterprise smtp routing: `generic, mimecast, pphosted, iphmx, barracuda, sophos, hornetsecurity, exchangedefender, mxfilter now use hybrid mode: direct first, proxy fallback`
- bulk resume sweep: `scheduler now re-attempts resumable queued/running bulk jobs every minute, so runs stranded by a restart or missed initial lock window can recover automatically`
- relay verdicts: `hard SMTP RCPT reject => invalid, provider signal positive => valid when available, accept-all relay => catch-all not valid`
- bulk CSV safe_to_send: `included in export; true only for strong valid verdicts with smtp=true, mailbox=true, catch_all=false`
- bulk direct-first behavior: `bulk runs no longer block the whole queue waiting for standard proxies before direct/hybrid providers can be checked`
- smtp proxy fallback policy: `hybrid/direct SMTP checks can proceed with zero ready standard proxies; proxy fallback is used only when available`
- DNS guardrails: `local DNS A/MX/TXT lookups are time-limited; MX failures on domains with valid A/AAAA now fall back to implicit RFC mail-host routing`
- self ping: `every 3 minutes`

## Fast Deploy

1. Edit local files.
2. Check syntax before deploy:
   - `node --check server/validators/smtp.js`
   - `node --check server/validators/providers.js`
   - `node --check server/validators/enterpriseProxyManager.js`
3. Upload changed files with cPanel Fileman `save_file_content`.
   - Use `dir=/home/zipperic48/api-validator.pinmarko.com/...`
   - Use `file=<name>`
   - Use `content@<local-file>` or `content=<raw text>`
   - Do not use multipart uploads for these saves.
4. Restart backend by updating:
   - `/home/zipperic48/api-validator.pinmarko.com/tmp/restart.txt`
   - `/home/zipperic48/api-validator.pinmarko.com/tmp-restart.txt`
5. Poll:
   - `https://api-validator.pinmarko.com/api/health`
6. Confirm:
   - `ready: true`
   - expected `version`

## Efficient Updates

- Backend only: change code under `server/`, upload just the touched files, restart, then health-check.
- Runtime-only knob change: upload `/home/zipperic48/api-validator.pinmarko.com/server/.env`, restart, then verify `/api/health` and relevant proxy status endpoint.
- Mimecast/enterprise proxy warmup after backend deploy: `POST /api/proxies/enterprise/refresh`, then poll `GET /api/proxies/enterprise/status` until active proxies > 0 before judging Mimecast results.
- Frontend only: build and deploy `dist/` to `/home/zipperic48/validator.pinmarko.com`.
- Shared change: update backend first, verify health, then update frontend if needed.
- Version bump: update `server/package.json` and redeploy so `/api/health` shows the new backend version.
- If health shows `503` or `ready: false`, wait briefly and recheck before retrying deploy.
