AutomationFlowsWeb Scraping › Masked Email Management for Fastmail

Masked Email Management for Fastmail

ByVitali @vquie on n8n.io

This n8n workflow is designed to manage Fastmail masked email addresses using the Fastmail API. The workflow provides the following functionalities: Retrieve all masked emails: Fetches all masked email addresses associated with the Fastmail account. Create masked email: Allows…

Webhook trigger★★★★☆ complexity11 nodesHTTP Request
Web Scraping Trigger: Webhook Nodes: 11 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #2448 — we link there as the canonical source.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "nodes": [
    {
      "id": "b1b6eb50-9d42-484d-9488-0607be2143d8",
      "name": "Session",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -160,
        -200
      ],
      "parameters": {
        "url": "https://api.fastmail.com/jmap/session",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "aca05a94-07dd-4408-8d87-47e788a5f0a8",
      "name": "get all masked emails",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "https://api.fastmail.com/.well-known/jmap\n\nhttps://api.fastmail.com/jmap/session",
      "position": [
        700,
        -200
      ],
      "parameters": {
        "url": "https://api.fastmail.com/jmap/api/",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"using\": [\"urn:ietf:params:jmap:core\", \"https://www.fastmail.com/dev/maskedemail\"],\n  \"methodCalls\": [\n    [\n      \"MaskedEmail/get\",\n      {\n        \"accountId\": \"{{ $('Session').item.json.primaryAccounts['https://www.fastmail.com/dev/maskedemail'] }}\"\n      },\n      \"c1\"\n    ]\n  ]\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "c4337bb4-1c16-4381-abe4-f0699099f326",
      "name": "create random masked email",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "https://api.fastmail.com/.well-known/jmap\n\nhttps://api.fastmail.com/jmap/session",
      "position": [
        540,
        40
      ],
      "parameters": {
        "url": "https://api.fastmail.com/jmap/api/",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"using\": [\n    \"urn:ietf:params:jmap:core\",\n    \"https://www.fastmail.com/dev/maskedemail\"\n  ],\n  \"methodCalls\": [\n    [\n      \"MaskedEmail/set\",\n      {\n        \"accountId\": \"{{ $('Session').item.json.primaryAccounts['https://www.fastmail.com/dev/maskedemail'] }}\",\n        \"create\": {\n          \"maskedEmailId1\": {\n            \"description\": \"Test via N8n\",\n            \"state\": \"{{ $('Webhook').item.json.body.state }}\",\n            \"id\": \"{{ $('Webhook').item.json.body.id }}\",\n            \"email\": \"{{ $('Webhook').item.json.body.email }}\"\n          }\n        }\n      },\n      \"c1\"\n    ]\n  ]\n}\n",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "bbfae2d8-d23a-4244-8566-c3da9cc2e34d",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1320,
        -200
      ],
      "parameters": {
        "options": {},
        "respondWith": "text",
        "responseBody": "={{ $json.html }}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "af8ac7a4-116f-41ef-b6c0-72006fb47474",
      "name": "Switch",
      "type": "n8n-nodes-base.switch",
      "position": [
        60,
        -200
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "pending",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Webhook').item.json.body.state }}",
                    "rightValue": "pending"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "enabled",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "56e6f1b8-0331-4c2d-aa90-e639752cfa9d",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Webhook').item.json.body.state }}",
                    "rightValue": "enabled"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "deleted",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "32f59847-a58c-4d8b-b1ae-48b8d4dad1a3",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Webhook').item.json.body.state }}",
                    "rightValue": "deleted"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "disabled",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "cc39f7c0-3960-49d9-ae21-9f1f35714015",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Webhook').item.json.body.state }}",
                    "rightValue": "disabled"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra"
        }
      },
      "typeVersion": 3.2
    },
    {
      "id": "ceca9fc2-e2f4-4578-8313-c987d08e9393",
      "name": "disabled",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "https://api.fastmail.com/.well-known/jmap\n\nhttps://api.fastmail.com/jmap/session",
      "position": [
        540,
        500
      ],
      "parameters": {
        "url": "https://api.fastmail.com/jmap/api/",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"using\": [\n    \"urn:ietf:params:jmap:core\",\n    \"https://www.fastmail.com/dev/maskedemail\"\n  ],\n  \"methodCalls\": [\n    [\n      \"MaskedEmail/set\",\n      {\n        \"accountId\": \"{{ $('Session').item.json.primaryAccounts['https://www.fastmail.com/dev/maskedemail'] }}\",\n        \"update\": {\n          \"{{ $('Webhook').item.json.body.id }}\": {\n            \"state\": \"{{ $('Webhook').item.json.body.state }}\"\n          }\n        }\n      },\n      \"c1\"\n    ]\n  ]\n}\n",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "c0467dec-a29e-42a0-8f81-fb12b0428974",
      "name": "delete",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "https://api.fastmail.com/.well-known/jmap\n\nhttps://api.fastmail.com/jmap/session",
      "position": [
        540,
        280
      ],
      "parameters": {
        "url": "https://api.fastmail.com/jmap/api/",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n    \"using\": [\n      \"urn:ietf:params:jmap:core\",\n      \"https://www.fastmail.com/dev/maskedemail\"\n    ],\n    \"methodCalls\": [\n      [\n        \"MaskedEmail/set\",\n        {\n          \"accountId\": \"{{ $('Session').item.json.primaryAccounts['https://www.fastmail.com/dev/maskedemail'] }}\",\n          \"destroy\": [\n            \"{{ $('Webhook').item.json.body.id }}\"\n          ]\n        },\n        \"c1\"\n      ]\n    ]\n  }\n  ",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "be0cdbe5-4607-44d5-8c51-7f8f1dcb4551",
      "name": "gather masked email list",
      "type": "n8n-nodes-base.set",
      "position": [
        920,
        -200
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "06210f93-1b2b-4bad-8a1d-263e57f651ca",
              "name": "data",
              "type": "array",
              "value": "={{ $json.methodResponses[0][1].list }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "bd4134cf-b684-4b6e-bb58-a70ff068e2fd",
      "name": "create html template",
      "type": "n8n-nodes-base.html",
      "position": [
        1120,
        -200
      ],
      "parameters": {
        "html": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Masked Email Addresses</title>\n    <style>\n        body {\n            font-family: Arial, sans-serif;\n            margin: 40px;\n            backgrouand-color: #f4f4f9;\n        }\n        h1 {\n            text-align: center;\n            color: #333;\n        }\n        .button-container, .filter-container, .table-container {\n            margin-bottom: 20px;\n            text-align: center;\n        }\n        button {\n            padding: 10px 20px;\n            margin: 0 10px;\n            font-size: 0.875em;\n            cursor: pointer;\n            background-color: #4CAF50;\n            color: white;\n            border: none;\n            border-radius: 3px;\n        }\n        .delete-button {\n            background-color: #f44336;\n        }\n        .disabled-button {\n            background-color: #ffa500;\n        }\n        select {\n            padding: 10px;\n            font-size: 0.875em;\n        }\n        table {\n            width: 100%;\n            border-collapse: collapse;\n            margin: 20px 0;\n            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);\n            background: #fff;\n        }\n        th, td {\n            border: 1px solid #ddd;\n            padding: 12px 15px;\n            text-align: left;\n            white-space: nowrap; /* Prevent text from wrapping */\n        }\n        th {\n            background-color: #f5f5f5;\n            color: #333;\n            text-transform: uppercase;\n            letter-spacing: 0.1em;\n            font-size: 0.875em;\n        }\n        tr:nth-child(even) {\n            background-color: #f9f9f9;\n        }\n        tr:hover {\n            background-color: #f1f1f1;\n        }\n        td {\n            font-size: 0.875em;\n        }\n        .action-cell {\n            display: flex;\n            justify-content: flex-end;\n        }\n    </style>\n</head>\n<body>\n    <h1>Masked Email Addresses</h1>\n    <div class=\"button-container\">\n        <button id=\"add-pending\">Add Pending</button>\n        <button id=\"add-enabled\">Add Enabled</button>\n    </div>\n    <div class=\"filter-container\">\n        <label for=\"state-filter\">Filter by State: </label>\n        <select id=\"state-filter\">\n            <option value=\"all\">All</option>\n        </select>\n    </div>\n    <div class=\"table-container\">\n        <table>\n            <thead>\n                <tr>\n                    <th>Email</th>\n                    <th>Description</th>\n                    <th>State</th>\n                    <th>Created By</th>\n                    <th>Created At</th>\n                    <th>Last Message At</th>\n                    <th>For Domain</th>\n                    <th>ID</th>\n                    <th>Actions</th>\n                </tr>\n            </thead>\n            <tbody id=\"table-body\">\n                <!-- Table rows will be populated here -->\n            </tbody>\n        </table>\n    </div>\n    <script>\n        // Convert JSON string to object\n        const responseString = `{{ $json.data.toJsonString() }}`;\n        const maskedEmails = JSON.parse(responseString);\n\n        // Populate the table\n        const tableBody = document.getElementById('table-body');\n        const stateFilter = document.getElementById('state-filter');\n\n        // Extract unique states\n        const uniqueStates = [...new Set(maskedEmails.map(email => email.state))];\n        uniqueStates.forEach(state => {\n            const option = document.createElement('option');\n            option.value = state;\n            option.textContent = state;\n            stateFilter.appendChild(option);\n        });\n\n        function populateTable(filteredEmails) {\n            tableBody.innerHTML = ''; // Clear the table body\n\n            filteredEmails.forEach(email => {\n                const row = document.createElement('tr');\n\n                // Populate table cells\n                const cellKeys = ['email', 'description', 'state', 'createdBy', 'createdAt', 'lastMessageAt', 'forDomain', 'id'];\n                cellKeys.forEach(key => {\n                    const cell = document.createElement('td');\n                    cell.textContent = email[key] !== null && email[key] !== undefined ? email[key] : 'N/A';\n                    row.appendChild(cell);\n                });\n\n                // Add action cell with delete and disable buttons\n                const actionCell = document.createElement('td');\n                actionCell.className = 'action-cell';\n\n                const deleteButton = document.createElement('button');\n                deleteButton.className = 'delete-button';\n                deleteButton.textContent = 'Delete';\n                deleteButton.addEventListener('click', () => updateMaskedEmail(email.id, email.email, 'deleted'));\n                actionCell.appendChild(deleteButton);\n\n                const disabledButton = document.createElement('button');\n                disabledButton.className = 'disabled-button';\n                disabledButton.textContent = 'Disable';\n                disabledButton.addEventListener('click', () => updateMaskedEmail(email.id, email.email, 'disabled'));\n                actionCell.appendChild(disabledButton);\n\n                row.appendChild(actionCell);\n\n                tableBody.appendChild(row);\n            });\n        }\n\n        // Initial population\n        populateTable(maskedEmails);\n\n        // Add event listener to filter dropdown\n        stateFilter.addEventListener('change', function() {\n            const selectedState = this.value;\n            const filteredEmails = selectedState === 'all' ? maskedEmails : maskedEmails.filter(email => email.state === selectedState);\n            populateTable(filteredEmails);\n        });\n\n        // Function to make POST request\n        function createMaskedEmail(state) {\n            fetch('/webhook/MaskedEmail', {\n                method: 'POST',\n                headers: {\n                    'Content-Type': 'application/json'\n                },\n                body: JSON.stringify({ state: state })\n            }).then(response => {\n                if (response.ok) {\n                    alert('New masked email created successfully!');\n                    // Reload the page after successful creation\n                    location.reload();\n                } else {\n                    alert('Error creating masked email');\n                }\n            }).catch(error => {\n                alert('Error: ' + error);\n            });\n        }\n\n        // Function to update masked email\n        function updateMaskedEmail(id, email, state) {\n            fetch('/webhook/MaskedEmail', {\n                method: 'POST',\n                headers: {\n                    'Content-Type': 'application/json'\n                },\n                body: JSON.stringify({ id: id, email: email, state: state })\n            }).then(response => {\n                if (response.ok) {\n                    alert(`Masked email ${state} successfully!`);\n                    // Reload the page after successful update\n                    location.reload();\n                } else {\n                    alert(`Error ${state} masked email`);\n                }\n            }).catch(error => {\n                alert('Error: ' + error);\n            });\n        }\n\n        // Event listeners for the buttons\n        document.getElementById('add-pending').addEventListener('click', () => createMaskedEmail('pending'));\n        document.getElementById('add-enabled').addEventListener('click', () => createMaskedEmail('enabled'));\n\n    </script>\n</body>\n</html>"
      },
      "typeVersion": 1.2
    },
    {
      "id": "a19b8aa6-b139-4011-8027-4cb1e7bef065",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -460,
        -200
      ],
      "parameters": {
        "path": "MaskedEmail",
        "options": {},
        "responseMode": "responseNode",
        "authentication": "basicAuth",
        "multipleMethods": true
      },
      "credentials": {
        "httpBasicAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "2c151e0a-1d67-4e84-8a6d-0e9cbe440b14",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -480,
        -20
      ],
      "parameters": {
        "width": 810.0000000000002,
        "height": 1181.829268292685,
        "content": "## Template Description\n\nThis n8n workflow is designed to manage Fastmail masked email addresses using the Fastmail API. The workflow provides the following functionalities:\n\n1. **Retrieve all masked emails**: Fetches all masked email addresses associated with the Fastmail account.\n2. **Create masked email**: Allows creating a new masked email with a specified state (`pending`, `enabled`, etc.).\n3. **Update masked email state**: Updates the state of a masked email such as enabling, disabling, or deleting it.\n4. **Generate HTML template**: Constructs an HTML table to display the masked emails in a user-friendly format.\n\n## Steps to Make it Work\n\n1. **Webhook Node**: \n   - This node listens for incoming requests to manage masked emails.\n   - Needs Basic Authentication credentials to secure the endpoint.\n\n2. **Session Node**: \n   - Sends a request to obtain session information from Fastmail's API.\n   - Requires an HTTP Header Auth credential with your Fastmail API token.\n\n3. **Switch Node**: \n   - Routes the workflow based on the state of the incoming masked email request (`pending`, `enabled`, `disabled`, `deleted`).\n   \n4. **HTTP Request Nodes**:\n   - These nodes handle various Fastmail API calls for masked emails (get, set, update, delete).\n   - All HTTP Request nodes require an HTTP Header Auth credential attached, using the Fastmail API token.\n\n5. **Set Node**: \n   - Gathers the retrieved masked email list into an array for further processing.\n\n6. **HTML Node**: \n   - Generates an HTML template to render the masked email addresses in a table format.\n\n7. **Respond to Webhook Node**: \n   - Sends back the HTML table to the client in response to the webhook request.\n\n### Needed Credentials\n\n1. **Fastmail Masked E-Mail Addresses**:\n   - An API token from Fastmail's API.\n   - Each HTTP call to Fastmail requires this credential for authentication.\n\n## Note\n\n- Ensure that you correctly configure authentication for the API calls and webhook security.\n- Use your actual Fastmail API credentials with the correct scope.\n- The workflow assumes that the Fastmail API is correctly configured and accessible from your n8n instance.\n- Update URLs and credentials IDs according to your n8n configuration."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Switch": {
      "main": [
        [
          {
            "node": "create random masked email",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "create random masked email",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "delete",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "disabled",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "get all masked emails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "delete": {
      "main": [
        [
          {
            "node": "get all masked emails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Session": {
      "main": [
        [
          {
            "node": "Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook": {
      "main": [
        [
          {
            "node": "Session",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Session",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "disabled": {
      "main": [
        [
          {
            "node": "get all masked emails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "create html template": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "get all masked emails": {
      "main": [
        [
          {
            "node": "gather masked email list",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "gather masked email list": {
      "main": [
        [
          {
            "node": "create html template",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "create random masked email": {
      "main": [
        [
          {
            "node": "get all masked emails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This n8n workflow is designed to manage Fastmail masked email addresses using the Fastmail API. The workflow provides the following functionalities: Retrieve all masked emails: Fetches all masked email addresses associated with the Fastmail account. Create masked email: Allows…

Source: https://n8n.io/workflows/2448/ — original creator credit. Request a take-down →

More Web Scraping workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Web Scraping

This n8n template provides enterprise-level version control for your workflows using GitHub integration. Stop losing hours to broken workflows and manual exports – get proper commit history, visual di

n8n, Execute Workflow Trigger, HTTP Request +1
Web Scraping

This flow creates dummy files for every item added in your *Arrs (Radarr/Sonarr) with the tag .

HTTP Request, Ssh
Web Scraping

This workflow acts as a central API gateway for all technical indicator agents in the Binance Spot Market Quant AI system. It listens for incoming webhook requests and dynamically routes them to the c

HTTP Request
Web Scraping

Sign PDF documents with legally-compliant digital signatures using X.509 certificates. Supports multiple PAdES signature levels (B, T, LT, LTA) with optional visible stamps.

Execute Command, HTTP Request, Read Write File +1
Web Scraping

📡 This workflow serves as the central Alpha Vantage API fetcher for Tesla trading indicators, delivering cleaned 20-point JSON outputs for three timeframes: , , and . It is required by the following a

HTTP Request