You are helping me send the member login emails of my Super website (super.so) from my own email address instead of Super's no-reply address.
How it works - keep to these facts:
- Super Memberships logs members in with a one-time link (works once, valid 1 hour). Under Site → Settings → Membership → Login settings I can set a "Login webhook URL" and turn on "Suppress login email" so Super sends nothing itself.
- For every login request of a real member, Super POSTs JSON to that URL: { "email": "...", "magicLinkUrl": "https://<my site>/...?membership_token=...", "expiresAt": "ISO date" }. The dashboard Test button sends the same shape with "test": true and the dummy link https://example.super.site/?membership_token=TEST_TOKEN. Super will not save a URL that has not passed a test.
- The request is not signed, and the visitor always sees "link sent" even if my automation fails.
- magicLinkUrl signs the holder in as that member, so it must only ever go to the member's inbox.
Build me an automation in {{n8n | Make | Zapier}} that does exactly this:
1. Trigger: incoming webhook (POST, JSON). I will append ?key={{a long random secret}} to its URL.
2. Guard - stop without sending unless: key equals my secret, email contains "@", and magicLinkUrl starts with https://{{my site domain(s)}}/ and contains membership_token= - or test is true.
3. Send one email to `email` from {{name <address>}} via {{Gmail | Outlook / Microsoft 365 | SMTP: host, port}}: subject "Your login link" (prefix "[TEST] " when test is true), an HTML body with my logo {{logo URL}}, accent colour {{#hex}}, a "Log in" button linking to magicLinkUrl, the member's email in bold, the expiry, the plain link as a fallback, and "Didn't ask for this? Ignore this email." Inline styles only. Click tracking off.
4. Do not log, store or forward the link anywhere else. Do not look anything up in Notion - Super only calls the webhook for members.
Output:
- n8n: a complete workflow JSON I can import (Webhook → Code → Send Email / Gmail node), credentials by reference only, successful executions not saved.
- Make / Zapier: numbered module-by-module steps with the exact field values, filter conditions and formulas. Remember Make filters are OR-of-ANDs.
- Then the switch-on steps in Super (paste URL with ?key=, Test, Save, turn on Suppress login email, publish the site once) and a test plan: test email arrives with [TEST]; a real login sends exactly one email from my address, not in spam, and the button signs me in; the login log shows Link sent (Webhook); a request without the key or with a foreign link sends nothing.
If you have the Super MCP server (https://mcp.super.so/mcp) connected, look up my site's domains with find_site / get_site instead of asking me. The login webhook itself is set in the dashboard, not through the MCP.
{
"name": "Super Membership login email (own Gmail / SMTP)",
"nodes": [
{
"name": "Super Login Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
0,
0
],
"webhookId": "967c1414-8ea4-4df4-978c-b5d4be850b15",
"notes": "Copy the Production URL, append ?key=<secretKey> and paste it into Super → Settings → Membership → Login webhook URL.",
"parameters": {
"httpMethod": "POST",
"path": "super-membership-login",
"responseMode": "onReceived",
"options": {}
},
"id": "45301fac-5483-4911-8ff7-ca3342a1d152"
},
{
"name": "Check & Build Email",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
220,
0
],
"parameters": {
"jsCode": "// ---- EDIT THIS BLOCK ONLY ------------------------------------------------\nconst CONFIG = {\n secretKey: \"REPLACE_WITH_A_LONG_RANDOM_STRING\", // the ?key=... you append to the webhook URL in Super\n siteDomains: [\"yoursite.com\", \"yoursite.super.site\"], // every domain your Super site answers on\n brandName: \"Your Brand\",\n logoUrl: \"https://yoursite.com/logo.png\",\n accent: \"#047857\",\n fromName: \"Your Brand\",\n fromEmail: \"hello@yoursite.com\", // must be allowed to send through your SMTP / Gmail account\n};\n// ---------------------------------------------------------------------------\n\nconst req = $input.first().json;\nconst body = req.body || {};\nconst email = String(body.email || \"\").trim().toLowerCase();\nconst link = String(body.magicLinkUrl || \"\");\nconst isTest = body.test === true;\n\n// Super does not sign the webhook: only a caller that knows the key, with a link to YOUR site, gets an email.\nconst keyOk = (req.query || {}).key === CONFIG.secretKey;\nconst linkOk = isTest || (link.includes(\"membership_token=\") &&\n CONFIG.siteDomains.some(d => link.startsWith(`https://${d}/`) || link.startsWith(`https://www.${d}/`)));\nif (!keyOk || !email.includes(\"@\") || !linkOk) return [];\n\nconst expires = body.expiresAt\n ? new Date(body.expiresAt).toUTCString().replace(\" GMT\", \" UTC\")\n : \"in one hour\";\nconst fill = (s) => s\n .replaceAll(\"{{LOGIN_URL}}\", link)\n .replaceAll(\"{{MEMBER_EMAIL}}\", email)\n .replaceAll(\"{{EXPIRES}}\", expires === \"in one hour\" ? expires : `at ${expires}`)\n .replaceAll(\"{{BRAND_NAME}}\", CONFIG.brandName)\n .replaceAll(\"{{LOGO_URL}}\", CONFIG.logoUrl)\n .replaceAll(\"{{ACCENT}}\", CONFIG.accent);\n\nconst TEMPLATE = \"<div style=\\\"margin:0;padding:0;background:#f7f7f5;font-family:Arial,Helvetica,sans-serif;color:#191918;\\\">\\n <div style=\\\"max-width:560px;margin:0 auto;padding:32px 20px;\\\">\\n <div style=\\\"background:#ffffff;border:1px solid #e6e3dc;border-radius:16px;overflow:hidden;\\\">\\n\\n <div style=\\\"padding:26px 32px 0;text-align:center;\\\">\\n <img src=\\\"{{LOGO_URL}}\\\" alt=\\\"{{BRAND_NAME}}\\\" width=\\\"120\\\"\\n style=\\\"display:block;width:120px;max-width:100%;height:auto;margin:0 auto;border:0;\\\" />\\n </div>\\n\\n <div style=\\\"padding:28px 32px 36px;\\\">\\n <h1 style=\\\"margin:0 0 16px;font-size:24px;line-height:32px;color:#191918;\\\">Your login link</h1>\\n\\n <p style=\\\"margin:0 0 24px;font-size:16px;line-height:26px;color:#55534e;\\\">\\n Click the button to sign in to {{BRAND_NAME}} as <strong style=\\\"color:#191918;\\\">{{MEMBER_EMAIL}}</strong>.\\n </p>\\n\\n <a href=\\\"{{LOGIN_URL}}\\\"\\n style=\\\"display:inline-block;background:{{ACCENT}};color:#ffffff;text-decoration:none;font-size:15px;font-weight:700;padding:14px 22px;border-radius:8px;\\\">\\n Log in →\\n </a>\\n\\n <p style=\\\"margin:24px 0 0;font-size:14px;line-height:22px;color:#55534e;\\\">\\n The link works once and expires {{EXPIRES}}. If the button does not work, copy this address into your browser:<br />\\n <a href=\\\"{{LOGIN_URL}}\\\" style=\\\"color:#55534e;word-break:break-all;\\\">{{LOGIN_URL}}</a>\\n </p>\\n\\n <p style=\\\"margin:24px 0 0;font-size:14px;line-height:22px;color:#8a8780;\\\">\\n Didn't ask for this? You can ignore this email - nobody can log in without the link.\\n </p>\\n </div>\\n </div>\\n </div>\\n</div>\";\n\nreturn [{ json: {\n to: email,\n from: `${CONFIG.fromName} <${CONFIG.fromEmail}>`,\n subject: `${isTest ? \"[TEST] \" : \"\"}Your login link`,\n html: fill(TEMPLATE),\n} }];"
},
"id": "43c7a3a7-27cc-45be-bd64-1d74f9167e74"
},
{
"name": "Send via SMTP",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2.1,
"position": [
440,
0
],
"notes": "SMTP credential: your provider's host/port/user. Gmail: smtp.gmail.com, 465, SSL, app password. Or replace with the Gmail / Microsoft Outlook node.",
"parameters": {
"fromEmail": "={{ $json.from }}",
"toEmail": "={{ $json.to }}",
"subject": "={{ $json.subject }}",
"emailFormat": "html",
"html": "={{ $json.html }}",
"options": {
"appendAttribution": false
}
},
"id": "8a67cbcf-5d72-44ea-8aa4-0883799f17c8"
}
],
"connections": {
"Super Login Webhook": {
"main": [
[
{
"node": "Check & Build Email",
"type": "main",
"index": 0
}
]
]
},
"Check & Build Email": {
"main": [
[
{
"node": "Send via SMTP",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"saveDataSuccessExecution": "none"
}
}
# Make scenario - Super login webhook → your Gmail / SMTP
Same logic as the n8n workflow, module by module. This is the setup we run for a customer's site: Custom
webhook → Gmail → Send an email from the owner's Google Workspace mailbox.
| # | Module | Settings |
|---|---|---|
| 1 | **Webhooks → Custom webhook** | Add a webhook, copy its address and append `?key=<long random string>`. Paste that into Super → Settings → Membership → Login webhook URL and press **Test** once, so Make learns the fields (`email`, `magicLinkUrl`, `expiresAt`, `test`, and `key` from the query string). |
| 2 | Filter on the link 1 → 3, **"Real Super login"** | Condition group 1 (AND): `key` *Equal to* your secret; `email` *Contains* `@`; `magicLinkUrl` *Starts with* `https://yoursite.com/`; `magicLinkUrl` *Contains* `membership_token=`. **OR** condition group 2 (AND): `key` *Equal to* your secret; `test` *Equal to (boolean)* `true`. Add one more OR group per extra site domain (e.g. `https://yoursite.super.site/`). |
| 3 | **Gmail → Send an email** - or **Microsoft 365 Email → Send an email**, or **Email → Send an email** with your own SMTP connection | To `{{1.email}}`. Subject `{{if(1.test; "[TEST] "; "")}}Your login link`. Content type HTML, body = `login-email.html` with `{{1.magicLinkUrl}}` in both `LOGIN_URL` places, `{{1.email}}` for `MEMBER_EMAIL`, and `{{formatDate(1.expiresAt; "HH:mm"; "Europe/London")}}` (your time zone) or the words "in one hour" for `EXPIRES`. From name: your brand. |
Make answers the webhook with 200 by itself; no Webhook response module is needed.
Settings worth changing in the scenario: **Scheduling → Immediately**; **Scenario settings → Data is
confidential** on, so Make does not keep the login link in the execution log.
**Traps we hit**
- Make filters are OR-of-ANDs: every condition inside one group must hold; the groups are alternatives. Putting
alternatives into one group makes the filter never pass, and the run still shows green with 1 operation.
A working run that sent mail shows 2 operations.
- Running the scenario with **Run once** does not feed the webhook a bundle. Press **Test** in Super, or post
JSON to the hook URL, to test it.
- Gmail sends as the connected Google account (or one of its verified "Send mail as" aliases). To send as
`hello@yourdomain.com` from a Google Workspace account, connect that mailbox.
**SMTP connection** (Email app): host and port from your provider - Resend `smtp.resend.com:465`, Postmark
`smtp.postmarkapp.com:587`, SendGrid `smtp.sendgrid.net:587` (user `apikey`), Brevo `smtp-relay.brevo.com:587`,
Gmail `smtp.gmail.com:465` with an app password. Turn the provider's click tracking off.
# Zapier Zap - Super login webhook → your Gmail / SMTP
Same logic as the n8n workflow, step by step. **Webhooks by Zapier** needs a paid Zapier plan.
| # | Step | Settings |
|---|---|---|
| 1 | **Trigger: Webhooks by Zapier → Catch Hook** | Copy the hook URL, append `?key=<long random string>`, paste it into Super → Settings → Membership → Login webhook URL and press **Test**. In Zapier, **Test trigger** picks up the request with `email`, `magicLinkUrl`, `expiresAt`, `test` and the `key` from the query string. |
| 2 | **Filter by Zapier** | Group 1 (AND): `key` *(Text) Exactly matches* your secret; `email` *(Text) Contains* `@`; `magicLinkUrl` *(Text) Starts with* `https://yoursite.com/`; `magicLinkUrl` *(Text) Contains* `membership_token=`. **OR** group 2: `key` *Exactly matches* your secret; `test` *(Boolean) Is true*. One more OR group per extra site domain. |
| 3 | **Formatter → Date / Time → Format** (optional) | Input `expiresAt`, format `HH:mm`, your time zone - for the "expires at" line. Or write "in one hour". |
| 4 | **Gmail → Send Email** - or **Microsoft Outlook → Send Email**, or **SMTP by Zapier → Send Email** | To step 1 `email`. Subject `Your login link` (add a second Zap path or a Formatter step for the `[TEST] ` prefix if you want it). Body type **HTML**, body = `login-email.html` with `magicLinkUrl` in both `LOGIN_URL` places, `email` for `MEMBER_EMAIL`, step 3 for `EXPIRES`. From name: your brand. |
Do not use **Email by Zapier**: it sends from a Zapier address, which is the opposite of the point and often
lands in spam.
Zapier keeps task history with the data of each step, including the login link. Links expire in one hour and
work once, but limit who can see the Zap history in your Zapier account.
**SMTP by Zapier**: host and port from your provider - Resend `smtp.resend.com:465`, Postmark
`smtp.postmarkapp.com:587`, SendGrid `smtp.sendgrid.net:587` (user `apikey`), Brevo `smtp-relay.brevo.com:587`,
Gmail `smtp.gmail.com:465` with an app password. Turn the provider's click tracking off.
<!--
Login email for a Super Memberships member. Inline styles only (email clients ignore <style>).
Placeholders: {{LOGIN_URL}} (magicLinkUrl from the webhook), {{MEMBER_EMAIL}}, {{EXPIRES}} (readable expiresAt),
{{BRAND_NAME}}, {{LOGO_URL}}, {{ACCENT}} (hex, e.g. #047857).
The button uses inline styles so it renders the same in Gmail, Outlook and Apple Mail.
-->
<div style="margin:0;padding:0;background:#f7f7f5;font-family:Arial,Helvetica,sans-serif;color:#191918;">
<div style="max-width:560px;margin:0 auto;padding:32px 20px;">
<div style="background:#ffffff;border:1px solid #e6e3dc;border-radius:16px;overflow:hidden;">
<div style="padding:26px 32px 0;text-align:center;">
<img src="{{LOGO_URL}}" alt="{{BRAND_NAME}}" width="120"
style="display:block;width:120px;max-width:100%;height:auto;margin:0 auto;border:0;" />
</div>
<div style="padding:28px 32px 36px;">
<h1 style="margin:0 0 16px;font-size:24px;line-height:32px;color:#191918;">Your login link</h1>
<p style="margin:0 0 24px;font-size:16px;line-height:26px;color:#55534e;">
Click the button to sign in to {{BRAND_NAME}} as <strong style="color:#191918;">{{MEMBER_EMAIL}}</strong>.
</p>
<a href="{{LOGIN_URL}}"
style="display:inline-block;background:{{ACCENT}};color:#ffffff;text-decoration:none;font-size:15px;font-weight:700;padding:14px 22px;border-radius:8px;">
Log in →
</a>
<p style="margin:24px 0 0;font-size:14px;line-height:22px;color:#55534e;">
The link works once and expires {{EXPIRES}}. If the button does not work, copy this address into your browser:<br />
<a href="{{LOGIN_URL}}" style="color:#55534e;word-break:break-all;">{{LOGIN_URL}}</a>
</p>
<p style="margin:24px 0 0;font-size:14px;line-height:22px;color:#8a8780;">
Didn't ask for this? You can ignore this email - nobody can log in without the link.
</p>
</div>
</div>
</div>
</div>