diff --git a/README.md b/README.md
index cb69951f5..303f9c945 100644
--- a/README.md
+++ b/README.md
@@ -36,15 +36,12 @@ Then send a `POST http://localhost:8080/v0/check_email` request with the followi
```js
{
"to_email": "someone@gmail.com",
- "from_email": "my@my-server.com", // (optional) email to use in the `FROM` SMTP command, defaults to "user@example.org"
- "hello_name": "my-server.com", // (optional) name to use in the `EHLO` SMTP command, defaults to "localhost"
"proxy": { // (optional) SOCK5 proxy to run the verification through, default is empty
"host": "my-proxy.io",
"port": 1080,
"username": "me", // (optional) Proxy username
"password": "pass" // (optional) Proxy password
},
- "smtp_port": 587 // (optional) SMTP port to do the email verification, defaults to 25
}
```
diff --git a/backend/README.md b/backend/README.md
index bd693811d..166d8a91e 100644
--- a/backend/README.md
+++ b/backend/README.md
@@ -9,10 +9,11 @@
-This crate holds the backend for [Reacher](https://reacher.email). The backend is a HTTP server with the following components:
+This crate holds the backend for [Reacher](https://reacher.email). The backend is both a HTTP server and a email verification worker. It has with the following components:
- [`check-if-email-exists`](https://github.com/reacherhq/check-if-email-exists), which performs the core email verification logic,
-- [`warp`](https://github.com/seanmonstar/warp) web framework.
+- [`warp`](https://github.com/seanmonstar/warp) web framework,
+- [`RabbitMQ`](https://www.rabbitmq.com/) worker for consuming a queue of incoming verification requests.
## Get Started
@@ -29,69 +30,22 @@ Then send a `POST http://localhost:8080/v0/check_email` request with the followi
```js
{
"to_email": "someone@gmail.com",
- "from_email": "my@my-server.com", // (optional) email to use in the `FROM` SMTP command, defaults to "user@example.org"
- "hello_name": "my-server.com", // (optional) name to use in the `EHLO` SMTP command, defaults to "localhost"
"proxy": { // (optional) SOCK5 proxy to run the verification through, default is empty
"host": "my-proxy.io",
"port": 1080,
"username": "me", // (optional) Proxy username
"password": "pass" // (optional) Proxy password
},
- "smtp_port": 587 // (optional) SMTP port to do the email verification, defaults to 25
}
```
-### Configuration
+## Configuration
-These are the environment variables used to configure the HTTP server. To pass them to the Docker container, use the `-e {ENV_VAR}={VALUE}` flag.
+The backend is configured via its [`backend_config.toml`](./backend_config.toml) file.
-| Env Var | Required? | Description | Dockerfile default |
-| ----------------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
-| `RUST_LOG` | No | One of `trace,debug,warn,error,info`. 💡 PRO TIP: `RUST_LOG=debug` is very handful for debugging purposes. | `reacher=info` |
-| `RCH_HTTP_HOST` | No | The host name to bind the HTTP server to. | `0.0.0.0` |
-| `PORT` | No | The port to bind the HTTP server to, often populated by the cloud provider. | `8080` |
-| `RCH_SENTRY_DSN` | No | If set, bug reports will be sent to this [Sentry](https://sentry.io) DSN. | not defined |
-| `RCH_HEADER_SECRET` | No | If set, then all HTTP requests must have the `x-reacher-secret` header set to this value. This is used to protect the backend against public unwanted HTTP requests. | undefined |
-| `RCH_FROM_EMAIL` | No | Email to use in the `` SMTP step. Can be overwritten by each API request's `from_email` field. | reacher.email@gmail.com |
-| `RCH_HELLO_NAME` | No | Name to use in the `` SMTP step. Can be overwritten by each API request's `hello_name` field. | gmail.com |
-| `RCH_SMTP_TIMEOUT` | No | Timeout for each SMTP connection. | 45s |
-| `RCH_WEBDRIVER_ADDR` | No | Set to a running WebDriver process endpoint (e.g. `http://localhost:9515`) to use a headless navigator to password recovery pages to check Yahoo and Hotmail/Outlook addresses. We recommend `chromedriver` as it allows parallel requests. | `http://localhost:9515` |
-| **For Bulk Verification:** | | |
-| `RCH_ENABLE_BULK` | No | If set to `1`, then bulk verification endpoints will be added to the backend. | 0 |
-| `DATABASE_URL` | Yes if `RCH_ENABLE_BULK==1` | [Bulk] Database connection string for storing results and task queue | not defined |
-| `RCH_DATABASE_MAX_CONNECTIONS` | No | [Bulk] Connections created for the database pool | 5 |
-| `RCH_MINIMUM_TASK_CONCURRENCY` | No | [Bulk] Minimum number of concurrent running tasks below which more tasks are fetched | 10 |
-| `RCH_MAXIMUM_CONCURRENT_TASK_FETCH` | No | [Bulk] Maximum number of tasks fetched at once | 20 |
+## API Documentation
-## REST API Documentation
-
-The API exposes the following endpoint: `POST /v0/check_email` expecting the following body:
-
-```js
-{
- "to_email": "someone@gmail.com",
- "from_email": "my@my-server.com", // (optional) email to use in the `FROM` SMTP command, defaults to "user@example.org"
- "hello_name": "my-server.com", // (optional) name to use in the `EHLO` SMTP command, defaults to "localhost"
- "proxy": { // (optional) SOCK5 proxy to run the verification through, default is empty
- "host": "my-proxy.io",
- "port": 1080,
- "username": "me", // (optional) Proxy username
- "password": "pass" // (optional) Proxy password
- },
- "smtp_port": 587 // (optional) SMTP port to do the email verification, defaults to 25
-}
-```
-
-For example, you can send the following `curl` request:
-
-```bash
-curl -X POST \
- -H'Content-Type: application/json' \
- -d'{"to_email":"someone@gmail.com"}' \
- http://localhost:8080/v0/check_email
-```
-
-Also check the [OpenAPI documentation](https://docs.reacher.email/advanced/openapi).
+See the full [OpenAPI documentation](https://docs.reacher.email/advanced/openapi).
## Build From Source
@@ -100,13 +54,10 @@ You can build the backend from source to generate a binary, and run the server l
```bash
# Download the code
$ git clone https://github.com/reacherhq/check-if-email-exists
-$ cd check-if-email-exists
-
-# Build the backend binary in release mode (more performant).
-$ cargo build --release --bin reacher_backend
+$ cd check-if-email-exists/backend
-# Run the binary with some useful logs.
-$ RUST_LOG=info ./target/release/reacher_backend
+# Run the backend binary in release mode (slower build, but more performant).
+$ cargo run --release --bin reacher_backend --features worker
```
The server will then be listening on `http://127.0.0.1:8080`.
diff --git a/backend/backend_config.toml b/backend/backend_config.toml
index a836bb69f..ee794ace9 100644
--- a/backend/backend_config.toml
+++ b/backend/backend_config.toml
@@ -1,40 +1,63 @@
-# Backend configuration
+# Backend configuration.
# Name to identify the backend.
+#
+# Env variable: RCH__BACKEND_NAME
backend_name = "backend-dev"
# Host to bind the backend to.
+#
+# Env variable: RCH__HTTP_HOST
http_host = "127.0.0.1"
# Port for the backend.
+#
+# Env variable: RCH__HTTP_PORT
http_port = 8080
# Shared secret between a trusted client and the backend, required in the
# `x-reacher-secret` header of all incoming requests.
+#
+# Env variable: RCH__HEADER_SECRET
# header_secret = "my-secret"
# Name to use during the EHLO/HELO command in the SMTP conversation.
# Ideally, this should match the reverse DNS of the server's IP address.
-hello_name = "reacher"
+#
+# Env variable: RCH__HELLO_NAME
+hello_name = "localhost"
# Email to use during the MAIL FROM command in the SMTP conversation.
# Ideally, the domain of this email should match the "hello_name" above.
-from_email = "reacher@gmail.com"
+#
+# Env variable: RCH__FROM_EMAIL
+from_email = "hello@localhost"
# Address of the Chrome WebDriver server for headless email verifications.
+#
+# Env variable: RCH__WEBDRIVER_ADDR
webdriver_addr = "http://localhost:9515"
# Timeout for each SMTP connection, in seconds. Leaving it commented out will
# not set a timeout, i.e. the connection will wait indefinitely.
+#
+# Env variable: RCH__SMTP_TIMEOUT
# smtp_timeout = 45
-# Uncomment the following lines to route all SMTP verification requests through
-# a specified proxy. Note that the proxy must be a SOCKS5 proxy to work with
-# the SMTP protocol. This proxy will not be used for headless verifications.
+# Uncomment the lines below to route all SMTP verification requests
+# through a specified proxy. Note that the proxy must be a SOCKS5 proxy to work
+# with the SMTP protocol. This proxy will not be used for headless
+# verifications.
#
# The username and password are optional and only needed if the proxy requires
# authentication.
-#
+#
+# Env variables:
+# - RCH__PROXY__HOST
+# - RCH__PROXY__PORT
+# - RCH__PROXY__USERNAME
+# - RCH__PROXY__PASSWORD
+#
# [proxy]
# host = "my.proxy.com"
# port = 1080
@@ -46,8 +69,12 @@ webdriver_addr = "http://localhost:9515"
# all email providers.
[verif_method]
# Gmail currently only supports the "smtp" method.
+#
+# Env variable: RCH__VERIF_METHOD__GMAIL
gmail = "smtp"
# Hotmail B2B currently only supports the "smtp" method.
+#
+# Env variable: RCH__VERIF_METHOD__HOTMAILB2B
hotmailb2b = "smtp"
# Hotmail B2C supports both "headless" and "smtp" methods. The "headless"
# method is recommended.
@@ -59,10 +86,13 @@ yahoo = "headless"
[worker]
# Enable the worker to consume emails from the RabbitMQ queues. If set, the
# RabbitMQ configuration below must be set as well.
+#
+# Env variable: RCH__WORKER__ENABLE
enable = true
# RabbitMQ configuration.
[worker.rabbitmq]
+# Env variable: RCH__WORKER__RABBITMQ__URL
url = "amqp://guest:guest@localhost:5672"
# Queues to consume emails from. By default, the worker consumes from all
@@ -78,10 +108,14 @@ url = "amqp://guest:guest@localhost:5672"
# - "check.yahoo": subscribe exclusively to Yahoo emails.
# - "check.everything_else": subscribe to all emails that are not Gmail, Yahoo, or Hotmail.
#
+# Env variable: RCH__WORKER__RABBITMQ__QUEUES
+#
# queues = ["check.gmail", "check.hotmail.b2b", "check.hotmail.b2c", "check.yahoo", "check.everything_else"]
queues = "all"
# Number of concurrent emails to verify for this worker across all queues.
+#
+# Env variable: RCH__WORKER__RABBITMQ__CONCURRENCY
concurrency = 20
# Throttle the maximum number of requests per second, per minute, per hour, and
@@ -91,6 +125,12 @@ concurrency = 20
# Important: these throttle configurations only apply to /v1/* endpoints, and
# not to the previous /v0/check_email endpoint. The latter endpoint always
# executes the verification immediately, regardless of the throttle settings.
+#
+# Env variables:
+# - RCH__WORKER__THROTTLE__MAX_REQUESTS_PER_SECOND
+# - RCH__WORKER__THROTTLE__MAX_REQUESTS_PER_MINUTE
+# - RCH__WORKER__THROTTLE__MAX_REQUESTS_PER_HOUR
+# - RCH__WORKER__THROTTLE__MAX_REQUESTS_PER_DAY
[worker.throttle]
# max_requests_per_second = 20
# max_requests_per_minute = 100
@@ -101,10 +141,10 @@ concurrency = 20
# the results of the verifications. This might change in the future, allowing
# for pluggable storage.
[worker.postgres]
+# Env variable: RCH__WORKER__POSTGRES__DB_URL
db_url = "postgresql://localhost/reacherdb"
-# Optional Sentry configuration. If set, all errors will be sent to Sentry.
-# [sentry]
-# dsn = ""
-# Identifier sent to Sentry, usually the same as the the top-level backend_name.
-# backend_name = "backend-dev"
+# Optional Sentry DSN. If set, all errors will be sent to Sentry.
+#
+# Env variable: RCH__SENTRY_DSN
+# sentry_dsn = ""
diff --git a/backend/src/config.rs b/backend/src/config.rs
index 4e9337852..4afdc103c 100644
--- a/backend/src/config.rs
+++ b/backend/src/config.rs
@@ -22,7 +22,7 @@ use crate::worker::setup_rabbit_mq;
use anyhow::bail;
use check_if_email_exists::{
CheckEmailInputProxy, GmailVerifMethod, HotmailB2BVerifMethod, HotmailB2CVerifMethod,
- YahooVerifMethod,
+ YahooVerifMethod, LOG_TARGET,
};
use config::Config;
#[cfg(feature = "worker")]
@@ -33,6 +33,7 @@ use sqlx::PgPool;
#[cfg(feature = "worker")]
use std::sync::Arc;
use std::{env, fmt};
+use tracing::warn;
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct BackendConfig {
@@ -370,6 +371,10 @@ pub async fn load_config() -> Result {
let mut cfg = cfg.try_deserialize::()?;
+ if !cfg.worker.enable && (cfg.worker.rabbitmq.is_some() || cfg.worker.throttle.is_some()) {
+ warn!(target: LOG_TARGET, "worker.enable is set to false, ignoring throttling and concurrency settings.")
+ }
+
let pg_pool = if cfg.worker.enable {
let db_url = cfg
.worker
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 3b3bbdd9c..310999239 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -24,7 +24,7 @@ services:
restart: always
worker1:
- image: reacherhq/backend:v0.10.0-beta.3
+ image: reacherhq/backend:beta
container_name: worker1
ports:
- "8080:8080"
@@ -38,10 +38,11 @@ services:
RCH__WORKER__ENABLE: true
RCH__WORKER__RABBITMQ__URL: amqp://guest:guest@rabbitmq:5672
RCH__WORKER__POSTGRES__DB_URL: postgres://postgres:postgres@postgres:5432/reacher_db
+ RCH__WORKER__THROTTLE__MAX_REQUESTS_PER_DAY: 10000 # Recommended limit per IP per day
restart: always
worker2:
- image: reacherhq/backend:v0.10.0-beta.3
+ image: reacherhq/backend:beta
container_name: worker2
ports:
- "8081:8080"
@@ -55,4 +56,5 @@ services:
RCH__WORKER__ENABLE: true
RCH__WORKER__RABBITMQ__URL: amqp://guest:guest@rabbitmq:5672
RCH__WORKER__POSTGRES__DB_URL: postgres://postgres:postgres@postgres:5432/reacher_db
+ RCH__WORKER__THROTTLE__MAX_REQUESTS_PER_DAY: 10000 # Recommended limit per IP per day
restart: always