reCAPTCHA & Outbound Email

The public chat page has no login, so AVA protects it with Google reCAPTCHA
v3
(invisible scoring — clients never solve a puzzle) plus server-side rate
limiting. Outbound transactional email goes through SMTP2GO. This page
covers both setups and the fail-closed rules that govern them.


Google reCAPTCHA v3

Create the site

At the Google reCAPTCHA admin console,
create a v3 site for your public chat hostname (e.g. chat.example.com).
Add localhost to the site's domains if you also want local development to
verify against the real service. Collect the two keys:

ValueMaps toExposure
Site keyNEXT_PUBLIC_RECAPTCHA_SITE_KEYPublic by design — baked into the browser bundle at build time (a Docker build arg; changing it requires a rebuild)
Secret keyRECAPTCHA_SECRET_KEYSecret — server-side verification only. Required to boot.

How verification behaves

  • Every chat-start (and the email-fallback form) submission carries a
    reCAPTCHA token that the server verifies against Google's siteverify
    endpoint before doing anything else.
  • Verification is score-based and rejects low-scoring (bot-like) tokens,
    tokens minted for a different action, and tokens minted on a different
    hostname.
  • The outbound call to Google has its own timeout (RECAPTCHA_TIMEOUT_MS,
    default 10000 ms), so a hung Google endpoint cannot stall requests.
  • Verification is fail-closed: a missing secret, a network error reaching
    Google, or an explicit failure from Google all reject the request. A Google
    outage cannot silently disable bot protection.

RECAPTCHA_DEV_BYPASS — development only, refused in production

For local development or CI where you don't want to configure real keys:

VariableDefaultEffect
RECAPTCHA_DEV_BYPASS(unset — fail closed everywhere)Set to the exact string true to fail open when verification can't complete (missing key or network error). Honored only when NODE_ENV is not production.

Two hard properties worth knowing:

  • It is refused outright in production. When NODE_ENV=production, the
    bypass is ignored no matter what the variable says — no runtime
    configuration can disable bot protection on a production deployment.
  • The match is exact: 1, yes, TRUE etc. do not activate it.

Since local development typically has a real RECAPTCHA_SECRET_KEY anyway
(with localhost on the site's domain list), most deployments never need this
variable at all.


SMTP2GO — outbound email

AVA sends three kinds of transactional mail:

MailTriggerRecipient variable
Support-request fallbackClient uses the "email us instead" path (after hours, or after a queue timeout)SUPPORT_FALLBACK_EMAIL
Engineer feedbackAn engineer submits feedback from the dashboardFEEDBACK_EMAIL
Weekly survey reportThe weekly CSAT report endpoint runs (guarded by WEEKLY_REPORT_TOKEN if you wire up a cron)REPORTS_EMAIL

Account setup

Create an SMTP2GO account and an SMTP user under it (Settings → SMTP
Users), and verify your sending domain so mail from your SMTP2GO_FROM
address passes SPF/DKIM. Then set:

VariableDefaultRequiredEffect
SMTP2GO_HOSTmail.smtp2go.comOptionalSMTP host
SMTP2GO_PORT2525OptionalSMTP port
SMTP2GO_USERRequired to bootSMTP username
SMTP2GO_PASSWORDRequired to bootSMTP password
SMTP2GO_FROMRequired for any mail to send (fail-closed)Sender address on all outbound mail, e.g. [email protected]
SMTP_TIMEOUT_MS10000OptionalSMTP connect + socket timeout

SMTP2GO_FROM is fail-closed. There is no built-in sender address: if
SMTP2GO_FROM is unset or empty, every email route refuses to send — the
attempt is logged as an error and the request returns a clean failure
instead of mailing from a made-up address. Set it to an address on a domain
your SMTP2GO account is authorized to send from.

While the SMTP transport is SMTP2GO-shaped by default, the host/port/user/
password are plain SMTP settings — another SMTP relay that accepts
username/password auth on these variables will also work.

Recipient configuration (fail-closed contract)

None of the recipient addresses have built-in defaults — a deployment can
never silently send mail to an address you didn't configure:

VariableRequiredBehavior when unset
SUPPORT_FALLBACK_EMAILRequired to boot — the container refuses to start without itn/a (boot-validated, so the client-facing email fallback always has a real destination)
FEEDBACK_EMAILOptionalThe feedback send is skipped and an error is logged — nothing is sent anywhere
REPORTS_EMAILOptionalThe report send is skipped and an error is logged — nothing is sent anywhere

SUPPORT_FALLBACK_EMAIL is boot-required because it backs a client-facing
promise: when chat is unavailable, the "email us a ticket" form must actually
deliver somewhere. The other two are internal conveniences and simply stay off
until you configure them.


Environment variable summary

VariableRequiredNotes
NEXT_PUBLIC_RECAPTCHA_SITE_KEYRequired at build timePublic site key, baked into the client bundle
RECAPTCHA_SECRET_KEYRequired to bootServer-side verification secret
RECAPTCHA_DEV_BYPASSOptional, dev-onlyExact true; ignored in production
RECAPTCHA_TIMEOUT_MSOptional (10000)siteverify fetch timeout
SMTP2GO_HOST / SMTP2GO_PORTOptionalDefaults mail.smtp2go.com / 2525
SMTP2GO_USER / SMTP2GO_PASSWORDRequired to bootSMTP credentials
SMTP2GO_FROMRequired for sending (fail-closed)Sender address
SUPPORT_FALLBACK_EMAILRequired to bootClient email-fallback recipient
FEEDBACK_EMAILOptional (fail-closed)Engineer feedback recipient
REPORTS_EMAILOptional (fail-closed)Weekly survey report recipient
WEEKLY_REPORT_TOKENOptionalBearer token for the weekly-report cron endpoint (openssl rand -hex 32); only needed if you schedule that report
SMTP_TIMEOUT_MSOptional (10000)SMTP connection/socket timeout

See configuration.md for the complete configuration
reference.


Next steps

  • quickstart.md — these values are set in the credential
    step of the bring-up.
  • white-label.md — the rest of the deployment identity
    (company name, phone, portal link) that appears alongside these email
    touchpoints.

Did this page help you?