Dropbox can notify your application when files change, but it cannot directly make an authenticated Volanea email API call for you. To send email from Dropbox reliably, use Dropbox Webhooks as the trigger, then let a server-side relay read the changed-file delta and call Volanea.
This distinction matters. Dropbox does offer an outbound webhook mechanism for Dropbox API apps, but the webhook message is deliberately small: it tells your endpoint that one or more Dropbox accounts have changed. It does not include a ready-to-email file record, a recipient, or an email body. Your relay is the secure and necessary hop that turns that notification into a useful, controlled email.
What this integration does—and does not do
This guide implements a practical file-activity workflow:
- A user or team member changes a file in a Dropbox account connected to your Dropbox API app.
- Dropbox sends your HTTPS webhook endpoint a notification containing the affected account ID or IDs.
- Your relay acknowledges the webhook immediately.
- A background worker uses the Dropbox
files/list_foldercursor API to retrieve the actual file changes. - The worker applies your business rules, such as watching
/Client Deliverablesand only acting on new PDF files. - The worker sends a transactional email through Volanea with the file path, event details, and an optional Dropbox link.
There is no native Volanea app in the Dropbox marketplace and no Dropbox setting where you paste a Volanea API key to create this connection. There is also no safe direct route from a browser-based Dropbox client to an email API: an email-sending key must remain secret.
The result is more flexible than a prebuilt connector. You can decide which paths count, which file types qualify, who receives the message, whether changed files should notify again, and how to prevent duplicate emails during retries.
The real Dropbox trigger: a file-change webhook notification
The concrete Dropbox-side trigger is a file or folder change in a Dropbox account that has authorized your Dropbox API app. Dropbox Webhooks notify your registered HTTPS endpoint that the account’s file listing has changed.
That is intentionally broader than a no-code trigger called “New File.” A file can be created, modified, moved, deleted, restored, or otherwise change the listing. Your code determines whether the particular delta entry is a new file worth emailing.
The webhook payload Dropbox actually sends
For file changes, Dropbox sends a JSON notification shaped like this:
{
"list_folder": {
"accounts": [
"dbid:AAH4f99T0taONIb-OurWxbNQ6ywGRopQngc"
]
}
}
The accounts array can contain more than one account ID. Do not assume exactly one account, and do not assume the identifier is an email address, a Dropbox path, a filename, or a user-facing name.
Most importantly, this payload does not contain the changed file’s metadata. It has no guaranteed name, path_display, id, size, content_hash, or shared-link field. Dropbox expects your app to keep a cursor for each connected account and call files/list_folder/continue after notification to retrieve the changes since the prior cursor.
Why Dropbox uses a notification instead of a full file event
A compact notification lets Dropbox batch changes and avoids placing potentially sensitive file metadata in every delivery. It also means a single webhook can represent many changes: uploading a folder, moving files, or a client synchronizing an existing directory can all result in one or more notifications.
Treat the webhook as a signal to synchronize state, not as an email instruction. The cursor-based delta is the source of truth for deciding whether to send.
Architecture: Dropbox webhook, relay, Volanea API
A sound implementation has four persistent pieces of state:
- Dropbox app credentials: the app key, app secret, and OAuth refresh token or another server-side token-management mechanism.
- Dropbox cursor per account: the latest successfully processed
files/list_foldercursor for each Dropbox account ID. - Delivery idempotency record: a durable key showing that a particular qualifying file revision or change has already produced an email.
- Volanea API key: stored only in a server-side secret store or protected environment variable.
The request path should be short:
Dropbox account changes
|
v
Dropbox Webhooks POST
|
v
Your HTTPS endpoint -- return 200 quickly --> Dropbox
|
v
Queue / background job
|
v
Dropbox files/list_folder/continue
|
v
Filter + deduplicate + map fields
|
v
Volanea REST API --> recipient inbox
This separation is not needless complexity. Webhook providers expect fast acknowledgements, while syncing a large folder and calling a delivery API can take longer or fail independently. A queue also gives you a place to retry Volanea failures without asking Dropbox to redeliver the original notification.
For Volanea request formats, authentication options, and sender-domain setup, keep the implementation aligned with the current email API reference and setup guides. Your relay should use the documented REST endpoint rather than attempting to send through an unauthenticated client-side integration.
Set up Dropbox Webhooks before writing the email logic
Create a Dropbox API app in the Dropbox App Console with the access model appropriate for the Dropbox content you need to monitor. The authorization and scopes must allow the app to read the files and folders that the connected user expects your workflow to watch.
Register a publicly reachable HTTPS callback URL in the app’s Webhooks configuration. Dropbox performs a validation request before using the endpoint: it sends a GET request containing a challenge query parameter. Your endpoint must return that challenge value as plain text.
Verify every POST notification
Dropbox signs webhook POST bodies with the app secret. Validate the X-Dropbox-Signature header against an HMAC-SHA256 of the raw request body using the Dropbox app secret.
Do this before parsing the notification as trusted input. Frameworks often parse JSON automatically, which can change whitespace or byte representation and make signature verification fail. Configure the webhook route to retain the raw bytes for validation.
A valid signature tells you that the message came from Dropbox, but it does not remove the need for application-level checks. You still need to verify that every dbid: account in the payload is an account your service has connected and that it has a stored cursor and valid OAuth authorization.
Establish the first cursor carefully
Before treating webhook notifications as actionable, establish a baseline cursor for each connected Dropbox account. Call files/list_folder for the folder you want to watch, save its returned cursor, and decide whether existing files should generate emails.
For most alert workflows, do not email the initial listing. Save the cursor after the initial scan, then alert only for later entries returned by files/list_folder/continue. Otherwise, connecting an account with years of documents could produce a large and unwanted email burst.
If you only monitor one directory, use that directory as the list-folder path. A narrow path reduces processing volume and gives the workflow a clear boundary. If you must inspect a tree, use recursive: true, then apply a strict path prefix in your worker as an additional guard.
Working Node.js relay: validate, sync, map, and send
The following Node.js example demonstrates the essential implementation. It handles Dropbox’s GET validation, validates the signed POST body, queues each account notification conceptually, retrieves cursor-based changes, and maps a qualifying Dropbox file into a Volanea email request.
The enqueueAccountSync, loadConnection, saveCursor, and claimDelivery functions represent your database and job queue. They must be durable in production; in-memory state is not enough for retries, redeployments, or concurrent webhook deliveries.
import crypto from "node:crypto";
import express from "express";
const app = express();
// Keep raw bytes on this route so Dropbox's HMAC can be checked correctly.
app.post("/webhooks/dropbox", express.raw({ type: "application/json" }), async (req, res) => {
const signature = req.get("X-Dropbox-Signature") || "";
const expected = crypto
.createHmac("sha256", process.env.DROPBOX_APP_SECRET)
.update(req.body)
.digest("hex");
const valid =
signature.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
if (!valid) return res.status(401).send("invalid signature");
const notification = JSON.parse(req.body.toString("utf8"));
const accounts = notification?.list_folder?.accounts || [];
// Acknowledge promptly. Do not wait for Dropbox API or Volanea API calls here.
res.sendStatus(200);
for (const accountId of accounts) {
await enqueueAccountSync({ provider: "dropbox", accountId });
}
});
// Dropbox webhook endpoint validation: return the query challenge as plain text.
app.get("/webhooks/dropbox", (req, res) => {
res.type("text/plain").send(req.query.challenge || "");
});
async function processDropboxAccount(accountId) {
const connection = await loadConnection(accountId);
if (!connection) return; // Ignore accounts that have not connected to your product.
let cursor = connection.cursor;
let page;
do {
const endpoint = cursor
? "https://api.dropboxapi.com/2/files/list_folder/continue"
: "https://api.dropboxapi.com/2/files/list_folder";
const requestBody = cursor
? { cursor }
: {
path: "/Client Deliverables",
recursive: true,
include_deleted: false
};
const dropboxResponse = await fetch(endpoint, {
method: "POST",
headers: {
Authorization: `Bearer ${connection.accessToken}`,
"Content-Type": "application/json"
},
body: JSON.stringify(requestBody)
});
if (!dropboxResponse.ok) {
throw new Error(`Dropbox list-folder request failed: ${dropboxResponse.status}`);
}
page = await dropboxResponse.json();
for (const entry of page.entries) {
// Dropbox returns deleted, folder, and file entries. Alert only on files.
if (entry[".tag"] !== "file") continue;
if (!entry.path_display?.startsWith("/Client Deliverables/")) continue;
if (!entry.name.toLowerCase().endsWith(".pdf")) continue;
// Prefer a stable file revision/content identifier where your business rule needs it.
// Your database should make this key unique to survive retries and concurrent workers.
const deliveryKey = `${accountId}:${entry.id}:${entry.rev}`;
const claimed = await claimDelivery(deliveryKey);
if (!claimed) continue;
const subject = `New Dropbox deliverable: ${entry.name}`;
const html = `
<p>A new PDF was detected in Dropbox.</p>
<ul>
<li><strong>File:</strong> ${escapeHtml(entry.name)}</li>
<li><strong>Path:</strong> ${escapeHtml(entry.path_display)}</li>
<li><strong>Size:</strong> ${entry.size.toLocaleString()} bytes</li>
<li><strong>Revision:</strong> ${escapeHtml(entry.rev)}</li>
</ul>
`;
// Send with Volanea's REST email endpoint and a server-side API key.
const volaneaResponse = await fetch("https://api.volanea.com/v1/emails", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VOLANEA_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
from: "Dropbox alerts <alerts@updates.example.com>",
to: ["ops@example.com"],
subject,
html
})
});
if (!volaneaResponse.ok) {
// Mark the claim retryable or use an outbox table before throwing.
throw new Error(`Volanea send failed: ${volaneaResponse.status}`);
}
await markDeliverySent(deliveryKey);
}
cursor = page.cursor;
await saveCursor(accountId, cursor);
} while (page.has_more);
}
function escapeHtml(value = "") {
return value.replace(/[&<>"']/g, ch => ({
"&": "&", "<": "<", ">": ">", '"': """, "'": "'"
}[ch]));
}
Field mapping in the example
The field mapping is intentionally explicit:
| Dropbox delta field | Volanea email field | Purpose |
|---|---|---|
entry.name | subject and HTML file label | Gives recipients a readable filename. |
entry.path_display | HTML path value | Shows where the file was detected. |
entry.size | HTML size value | Adds lightweight context without downloading the file. |
entry.rev | HTML revision and idempotency key | Identifies the file revision that triggered the alert. |
entry.id plus entry.rev | delivery idempotency key | Prevents repeated notifications for the same processed revision. |
| configured recipient | to | Keeps recipient choice out of untrusted file metadata. |
| verified sender domain | from | Uses a domain you control and have configured for sending. |
The example does not attach the Dropbox file. That is deliberate. File attachments require a separate download step, size controls, malware policy, content-type validation, and an explicit decision about whether the recipient should receive a copy of private content by email. In many cases, an alert with a controlled shared link is safer than an attachment.
Keep Volanea and Dropbox credentials server-side
Put VOLANEA_API_KEY in your hosting provider’s encrypted environment-variable store, secret manager, or workload identity-backed secret service. The same principle applies to the Dropbox app secret and OAuth refresh token.
Do not put the Volanea key in any of these places:
- a Dropbox file or shared folder;
- a JavaScript bundle that runs in a browser;
- a Dropbox client-visible configuration file;
- a frontend environment variable with a public prefix;
- a webhook URL query string;
- application logs, error messages, or email templates;
- a no-code connection field that exposes secrets to untrusted collaborators.
A Volanea API key authorizes sending. If exposed, it can be abused to send mail as your account, damage sender reputation, consume sending volume, and create incident-response work. Rotate it immediately if you suspect exposure, then update the secret in the relay rather than redeploying it into client code.
Separate app configuration from secrets
It is fine to keep non-sensitive rules in a configuration record: watched path, allowed extensions, recipient group ID, template identifier, and whether modifications should notify. It is not fine to put raw API credentials in that record if administrators, Dropbox collaborators, browser users, or support tooling can read it.
Use server-controlled recipient rules as well. Do not derive an email recipient directly from a filename, folder name, or arbitrary file metadata without validation. A document named invoice--ceo@example.com.pdf should not be able to redirect an internal alert.
Decide exactly which Dropbox changes should send email
A file-change notification is broader than a “new upload” event, so define the business event in code. A good rule has a location, object type, state, and recipient policy.
For example: “When a PDF file appears under /Client Deliverables/ after initial connection, email the operations distribution list once for that file revision.” That rule is testable. “When Dropbox changes, email someone” is not.
Useful filtering rules
Consider combining several conditions:
- Require
entry[".tag"] === "file"so folders and deleted entries do not generate mail. - Require a path prefix such as
/Client Deliverables/. - Allow a small set of extensions, such as
.pdf,.csv, or.xlsx. - Ignore temporary names, hidden working files, and known sync artifacts.
- Require a minimum or maximum size where appropriate.
- Decide whether a new
revfor an existingidshould notify again. - Use an allowlist of connected account IDs and recipient groups.
Dropbox may return a changed file after a move, modification, or restore. If your business intent is “new file only,” you need a state model that records previously observed file IDs, not merely a check for a file entry. If your intent is “new revision requires review,” then using file ID plus revision is appropriate.
Do not email raw filenames without escaping
Dropbox filenames are user-controlled input. Escape them before putting them in HTML, as the code does. For a plain-text part, avoid interpreting a filename as a URL or command. If you create links, construct them from trusted API output and validate the destination domain.
This is a small but important second-order consequence of treating cloud-storage metadata as content. A file name may contain markup-looking characters, misleading text, or personal information. Keep notifications minimal and useful.
When this breaks: Dropbox-to-email failure modes
The fragile point is not merely “Dropbox is down” or “the email API is down.” It is the boundary between an at-least-once Dropbox notification and a potentially billable, recipient-visible email send.
Dropbox retries can cause duplicate sends
Dropbox can deliver notifications again when it does not receive a successful acknowledgement or when a delivery is retried. Multiple notifications can also legitimately arrive for a burst of changes. Never equate one webhook POST to one email.
Return a successful response quickly after signature verification and queueing. Then use a database-backed unique idempotency key before sending. For the file-revision alert shown above, accountId + entry.id + entry.rev is a reasonable starting key. If your workflow sends only once per file regardless of revisions, use the file ID and encode that policy explicitly.
Do not mark an item permanently sent before the email provider accepts it. A robust pattern is an outbox record with states such as pending, sending, sent, and retryable, plus a unique constraint on the business key. This lets a worker recover after a process crash between the API call and state update.
Webhook timeouts and slow processing
A common mistake is downloading files, iterating a full folder tree, generating PDFs, and sending email inside the webhook HTTP handler. That risks a timeout and a retry even if the work eventually succeeds.
The handler should validate, enqueue, and return. The asynchronous job can page through has_more, retry transient Dropbox or Volanea errors with backoff, and expose its own monitoring. A queue is especially valuable when an account makes many changes quickly.
Missing or unavailable fields
The webhook payload only carries account IDs, so file fields are absent by design until you call the Dropbox files API. Even in returned metadata, do not assume every optional field is available for every account type, permission arrangement, path, or Dropbox feature set.
Build the email from a minimum safe set—such as name, id, rev, and path_display when present—and use fallbacks. Do not make a shared-link URL, team information, or ownership metadata a mandatory dependency unless your app has the necessary access and you have tested the relevant account configurations. Dropbox plans, team settings, app scopes, and folder permissions can affect what your application can access.
Expired authorization and revoked access
A connected user can revoke your app, a token can expire, or access to the watched folder can change. When Dropbox returns an authorization or access error, stop blindly retrying and mark the connection as requiring reauthorization. Notify an administrator through a separate trusted channel rather than repeatedly attempting to send incomplete alerts.
Sender-domain and recipient problems
A Volanea request can be accepted or rejected independently of the Dropbox sync. Make sure the from address uses a domain you have configured for email sending, and handle validation errors separately from transient server errors. If recipient addresses come from a database, validate and suppress known bad addresses before sending; for one-off checks, a free email address verification tool can help catch obvious address issues before a workflow is activated.
Testing the workflow without spamming real recipients
Start with a staging Dropbox app, a dedicated test folder, a verified test sender, and a mailbox you control. Do not point an early integration at a production team folder.
Use a test matrix that covers more than a successful upload:
- Initial account connection: confirm the baseline cursor creates no email.
- New qualifying PDF: confirm exactly one message with the expected filename and path.
- New non-qualifying file: confirm no message.
- File modification: confirm behavior matches your revision policy.
- File move into the watched path: confirm whether it should count as an alert.
- Deleted file: confirm it does not create an accidental “new file” email.
- Replayed webhook: confirm the idempotency table blocks a duplicate.
- Multiple-account notification: confirm each account is processed independently.
- Revoked Dropbox authorization: confirm the connection enters a recoverable error state.
- Volanea API failure: confirm the outbox retries without re-syncing or duplicating messages.
Log stable identifiers rather than sensitive content. A useful structured log includes the Dropbox account ID, cursor, file ID, revision, idempotency key, queue job ID, Volanea response status, and delivery message ID if returned. Avoid logging access tokens, API keys, full email bodies, or file contents.
Alternatives when you do not want to operate a relay
Dropbox Webhooks give you direct outbound HTTP notifications, but they still need an endpoint that understands the payload and performs the cursor sync. If you do not want to operate that endpoint, a workflow platform can be the middleware layer.
Zapier and Make offer Dropbox triggers and can send an HTTP request to an email API, subject to their available actions, plan limits, polling or trigger behavior, secret handling, and error-retry controls. This can be suitable for a low-volume internal alert with a simple rule.
However, inspect the platform’s exact Dropbox trigger semantics before relying on it. A trigger called “new file” may have different folder, team, deduplication, or timing behavior than Dropbox’s native webhook-plus-cursor model. Also confirm that the platform can securely store a Volanea key, call the required REST endpoint, and preserve enough information to avoid duplicate sends.
For compliance-sensitive, high-volume, or customer-facing email, the direct webhook relay is usually the clearer architecture. You own the state, filtering, audit trail, retries, credential boundary, and failure policy rather than translating them through a third-party workflow abstraction.
Operational guidance for production
Monitor both halves of the pipeline. A healthy webhook endpoint is not proof that emails are being sent, and successful Volanea sends are not proof that Dropbox changes are being discovered.
Track at least these operational measures:
- webhook requests received and signature failures;
- queue depth and age of the oldest job;
- cursor-sync success and failure counts by account;
- number of changed entries examined versus qualifying entries;
- duplicate claims prevented;
- Volanea send acceptance, rejection, and retry counts;
- authorization failures requiring user action;
- time from Dropbox notification to email submission.
Set limits too. A compromised or misconfigured Dropbox account could create a large number of files. Per-account rate limits, a daily alert ceiling, extension allowlists, and anomaly alerts protect recipients and your sending reputation. If a backlog grows, it is generally better to delay noncritical alerts than to send thousands of low-value messages at once.
Conclusion: treat Dropbox as the signal and Volanea as the sender
The dependable way to send email from Dropbox is not a marketplace installation or a client-side API call. It is a small server-side integration that accepts Dropbox’s signed file-change notification, uses a stored cursor to discover the real changes, applies explicit business rules, and sends a properly authenticated Volanea email.
That architecture solves the details that make automations reliable in practice: Dropbox’s compact webhook payload, fast acknowledgement expectations, duplicate deliveries, evolving file metadata, protected API keys, and email-specific sender controls. Start with one watched folder and one test recipient, persist your cursors and idempotency keys, then expand the rules only after the basic path is observable and stable.
FAQ
Can Dropbox directly call Volanea with my API key?
Dropbox Webhooks can call your HTTPS endpoint, but Dropbox does not provide a native Volanea connector that securely stores and submits your Volanea API key. Use a server-side relay or a carefully configured middleware platform so the key remains private.
What Dropbox event starts the email?
The native trigger is a Dropbox Webhooks notification that the connected account’s file listing changed. The notification contains affected account IDs; your relay then calls the cursor-based Dropbox files API to determine which actual file entries qualify for an email.
Why does the webhook payload not include the filename?
Dropbox Webhooks are notifications, not complete file-event records. The list_folder.accounts payload tells your app which account changed. Use files/list_folder or files/list_folder/continue with a stored cursor to retrieve file metadata and changes.
How do I stop duplicate Dropbox alert emails?
Acknowledge webhooks quickly, process changes asynchronously, and store a unique idempotency key before sending. For revision-level alerts, a key composed of the Dropbox account ID, file ID, and revision is a practical approach.
Should I attach the changed Dropbox file to the email?
Only if your security and size policies require it. Downloading and attaching files adds access-control, content-validation, malware-scanning, and attachment-size concerns. An alert containing safe metadata and a controlled link is often the better default.