Streamlining optional file Attachment processing for Brevo module: Avoiding 16+ separate filter branches

Hello!

I am working on a complex, multi-step form where users are required to upload between 2 to 8 optional file attachments (documents like PNG, JPG, PDF).

My goal is to send all these files in a single email via the Brevo (Send an Email) module.

Current Problem and Complexity:

Since the file upload fields are dynamic and optional, I receive up to 16 unique combinations of present/missing files for each client type. For instance, in one case, a client uploads only 5 photos (out of 8), and in another, only 2 photos (out of 8). The number of files varies widely in different combinations.

The Brevo module, when using Map mode for Attachments, is very strict: it throws an error if a variable passed into the attachment array is equal to null (meaning the file was not uploaded by the user).

To circumvent this, I currently have to create 16 separate branches (routes), each with unique filters. At the end of each branch is a dedicated Brevo module, strictly configured for the specific combination of files that are guaranteed to be present. This makes the scenario extremely cumbersome and difficult to maintain.

Seeking a Cleaner, Unified Solution:

I believe there must be a standard solution to this problem, allowing me to use just one branch for email sending. The required logic is as follows:

  1. Gather all 8 potential file variables into a single array.

  2. Automatically prune (filter out) all elements that are equal to null (empty fields).

  3. Pass the resulting “clean” array into the Attachments (Map) field of the Brevo module.

Question:

Could you please advise on the simplest way in Make.com to perform this specific filtering? Is there a special built-in function that works within the Attachments field (ignoring null), or is there a more elegant use of Iterator and Array Aggregator that can help me avoid these 16 separate branches?

Thank you for any assistance!


P.S. I attempted the following solution unsuccessfully:

“We tried to pass an array of optional attachments from a Webhook to the Brevo (Send an Email) module. To filter out null elements (empty values), we attempted to create a clean array using standard array functions. Our scenario does not accept any expression intended for array creation or filtering, resulting in the error: Function 'array' not found! This error occurs not only in the Attachments field of the Brevo module, but also within the Set Multiple Variables and Iterator modules. This blocking makes it impossible to use constructs like array(), merge(), and if() / array() to cleanly construct the attachment array.”

Hey @Andrejs - can you provide a sample of what your webhook payload looks like when it’s received in Make?

If you could provide two different cases (eg one where user uploaded 2 out of 8, and one where they uploaded 5 out of 8), that would be great.

Make sure you redact or sanitize any personal information.

Cheers

Hello Sierra,

Thank you so much for the response!

Here are the two sample payloads from the Webhook, sanitized of personal data. The core difficulty lies in the varying number of files across two different “steps” or phases within the form:

### The Core Problem: Varying Combinations Across Two Steps

The total number of attachments can vary from 2 up to 8. These files are split across two logical steps (Step A and Step B), each potentially having 4 optional fields.

* **Step A:** 1 to 4 optional photos

* **Step B:** 1 to 4 optional photos

This creates a high number of unique combinations (e.g., 4 files in Step A + 2 files in Step B = 6 total files), resulting in the need for an unmanageable number of **filter routes (16+ branches)** if I cannot filter out the ‘null’ fields dynamically.

I am essentially looking for a single, elegant solution to process all 8 potential fields simultaneously.

### Sample Payloads (Sanitized)

**Case 1: 4 Files Present (from 8 Total)**

[

{

    "techPassportFrontLegal": {

        "name": "PL-techPass.pdf",

        "mime": "application/pdf",

        "data": "IMTBuffer(1453739, binary, 6d1a00479dd8dae6ee5fef0a05b02f291d162362): 255044462d312e340d25e2e3cfd30d0a312030206f626a0d3c3c200d2f43726561746f72202843616e6f6e20534331303131290d2f4372656174696f6e446174652028443a32303234303931373039333931332b303127303027290d2f50726f64756365",

        "files": \[

            {

                "name": "PL-techPass.pdf",

                "mime": "application/pdf",

                "data": "IMTBuffer(1453739, binary, 6d1a00479dd8dae6ee5fef0a05b02f291d162362): 255044462d312e340d25e2e3cfd30d0a312030206f626a0d3c3c200d2f43726561746f72202843616e6f6e20534331303131290d2f4372656174696f6e446174652028443a32303234303931373039333931332b303127303027290d2f50726f64756365"

            }

        \]

    },

    "techPassportBackLegal": {

        "name": "EST-tecchPass.pdf",

        "mime": "application/pdf",

        "data": "IMTBuffer(395153, binary, d096ab2a3f44a086172edf4783a1049cce31d184): 255044462d312e340a25e2e3cfd30d0a352030206f626a0a3c3c0a2f54797065202f584f626a6563740a2f53756274797065202f496d6167650a2f4e616d65202f496d300a2f576964746820313635330a2f48656967687420323333380a2f4269747350",

        "files": \[

            {

                "name": "EST-tecchPass.pdf",

                "mime": "application/pdf",

                "data": "IMTBuffer(395153, binary, d096ab2a3f44a086172edf4783a1049cce31d184): 255044462d312e340a25e2e3cfd30d0a352030206f626a0a3c3c0a2f54797065202f584f626a6563740a2f53756274797065202f496d6167650a2f4e616d65202f496d300a2f576964746820313635330a2f48656967687420323333380a2f4269747350"

            }

        \]

    },

    "directorPassportLegal": {

        "name": "PL_PASS.jpeg",

        "mime": "image/jpeg",

        "data": "IMTBuffer(299709, binary, 8ee98f5cd3a4ea9ab0f54a3a02928843c9fcf820): ffd8ffdb00430006040506050406060506070706080a100a0a09090a140e0f0c1017141818171416161a1d251f1a1b231c1616202c20232627292a29191f2d302d283025282928ffdb0043010707070a080a130a0a13281a161a28282828282828282828",

        "files": \[

            {

                "name": "PL_PASS.jpeg",

                "mime": "image/jpeg",

                "data": "IMTBuffer(299709, binary, 8ee98f5cd3a4ea9ab0f54a3a02928843c9fcf820): ffd8ffdb00430006040506050406060506070706080a100a0a09090a140e0f0c1017141818171416161a1d251f1a1b231c1616202c20232627292a29191f2d302d283025282928ffdb0043010707070a080a130a0a13281a161a28282828282828282828"

            }

        \]

    },

    "insuranceTermLegal": "6",

    "startDateLegal": "2025-11-12",

    "regNumber": "1WERT23CV",

    "contactFullName": "Aleksandr Ninov",

    "contactEmail": "alek.nin.56@mail.com",

    "contactPhone": "27994554213",

    "entityType": "Юридическое Л.",

    "directorPassportLegalBack": {

        "name": "LT_PASS.pdf",

        "mime": "application/pdf",

        "data": "IMTBuffer(494334, binary, 98cb8651d06db3919cb0db85e853cbd4a1a50d67): 255044462d312e340a25e2e3cfd30d0a312030206f626a0a3c3c200a2f43726561746f72202843616e6f6e204d46373332432f373334432f37333543290a2f4372656174696f6e446174652028443a32303230313130363230303932372b303227303027",

        "files": \[

            {

                "name": "LT_PASS.pdf",

                "mime": "application/pdf",

                "data": "IMTBuffer(494334, binary, 98cb8651d06db3919cb0db85e853cbd4a1a50d67): 255044462d312e340a25e2e3cfd30d0a312030206f626a0a3c3c200a2f43726561746f72202843616e6f6e204d46373332432f373334432f37333543290a2f4372656174696f6e446174652028443a32303230313130363230303932372b303227303027"

            }

        \]

    }

}

]

**Case 2: 2 Files Present (from 8 Total)**

[

{

    "techPassportFrontLegal": {

        "name": "PL-techPass.pdf",

        "mime": "application/pdf",

        "data": "IMTBuffer(1453739, binary, 6d1a00479dd8dae6ee5fef0a05b02f291d162362): 255044462d312e340d25e2e3cfd30d0a312030206f626a0d3c3c200d2f43726561746f72202843616e6f6e20534331303131290d2f4372656174696f6e446174652028443a32303234303931373039333931332b303127303027290d2f50726f64756365",

        "files": \[

            {

                "name": "PL-techPass.pdf",

                "mime": "application/pdf",

                "data": "IMTBuffer(1453739, binary, 6d1a00479dd8dae6ee5fef0a05b02f291d162362): 255044462d312e340d25e2e3cfd30d0a312030206f626a0d3c3c200d2f43726561746f72202843616e6f6e20534331303131290d2f4372656174696f6e446174652028443a32303234303931373039333931332b303127303027290d2f50726f64756365"

            }

        \]

    },

    "insuranceTermLegal": "12",

    "startDateLegal": "2025-12-18",

    "regNumber": "DF34VBHH98",

    "contactFullName": "Pontij Wasonok",

    "contactEmail": "ponty_78@yahoo.com",

    "contactPhone": "2479954676766",

    "entityType": "Юридическое Л.",

    "directorPassportLegal": {

        "name": "PL_PASS.jpeg",

        "mime": "image/jpeg",

        "data": "IMTBuffer(299709, binary, 8ee98f5cd3a4ea9ab0f54a3a02928843c9fcf820): ffd8ffdb00430006040506050406060506070706080a100a0a09090a140e0f0c1017141818171416161a1d251f1a1b231c1616202c20232627292a29191f2d302d283025282928ffdb0043010707070a080a130a0a13281a161a28282828282828282828",

        "files": \[

            {

                "name": "PL_PASS.jpeg",

                "mime": "image/jpeg",

                "data": "IMTBuffer(299709, binary, 8ee98f5cd3a4ea9ab0f54a3a02928843c9fcf820): ffd8ffdb00430006040506050406060506070706080a100a0a09090a140e0f0c1017141818171416161a1d251f1a1b231c1616202c20232627292a29191f2d302d283025282928ffdb0043010707070a080a130a0a13281a161a28282828282828282828"

            }

        \]

    }

}

]

**Note on Nulls:** In both cases, the missing fields are either explicitly passed as `null` or are entirely omitted from the payload, which leads to the Brevo module failure when attempting to process the attachment array.

Thank you again for looking into this! Your willingness to help is greatly appreciated, especially as I am still very new to Make. I really hope there is a cleaner way to solve this than manual routing.

Best regards,

Aleks

Thanks for the sample Aleks - super helpful! The payload is actually perfect and allows for a really elegant solution.

Add this scenario to your account:

Here’s how it works:

  1. First module is just a helper module so I can reproduce your webhook input, you won’t need it in your scenario and can ignore it
  2. Iterator: you’ll combine the files array from all 8 of your file objects with merge(), for example:
{{merge(1.techPassportFrontLegal.files; 1.techPassportBackLegal.files; 1.directorPassportLegal.files; 1.directorPassportLegalBack.files; 1.OTHER_FIELDS.files)}}

  1. Aggregator: before you configure this module, connect the Brevo module after it. It doesn’t have to be placed immediately after the aggregator, just has to be somewhere after it
  2. Then configure aggregator like this:
    Source module: Iterator
    Target structure type: Attachments (from Brevo)
    Attachments > Type: Data
    File name: name from iterator (you can manually map this by typing {{X.name}} where X is the iterator’s module number)
    Data: data from iterator (same as above, map it manually by typing {{X.data}}

  1. Brevo: map the output of the aggregator to attachments

Done!

If you might have files arrays coming through as null, or somehow still passing through to the aggregator, you can put a filter between the iterator and aggregator. This should work, for example:

Cheers!

4 Likes

Hey! I just want to say a big thank you for your help with the project — your scheme with Iterator and Array Aggregator really saved the situation. Now everything works: merge() collects the files, the filter removes the empty ones, and Brevo receives exactly what it needs. Instead of those awful 16 branches, I now have just one, exactly as I wanted. In my opinion, it’s an excellent yet simple and professional solution!

Thanks again! My horizons in Make.com have expanded once more :slightly_smiling_face:

1 Like

Hello esteemed Make.com experts!

My name is Alex, and I am reaching out for assistance once again. Thank you so much for the brilliant solution to my previous problem—the Iterator + Array Aggregator schema worked flawlessly!

I apologize for returning to this thread, even though it was marked as solved. The issue arose because we had to implement Cloudinary for file optimization, and now our Webhook receives only URL links instead of the files themselves. This external change has broken our working automation.

Project Summary:

Goal: Process anywhere from 2 to 8 files (all are optional fields) and attach them all to a single email using the Brevo module.

Previous Working Solution: When the Webhook received binary file data, the schema was: Webhook → Iterator (with merge formula for .files) → Filter → Aggregator → Brevo.

The New Problem: URLs and the HTTP Module

We adapted the schema by adding the file download step: Webhook → Iterator (to collect URLs) → Filter → HTTP - Get a File (to download the file) → Array Aggregator → Brevo

The Core Failure: Creating a Clean URL Array

We suspect the problem lies in the Iterator module. It fails to reliably create a clean array of URL strings because:

We need to collect all 8 potential URL variables coming from the Webhook.

We must automatically exclude variables that contain null or an empty string (the optional fields that were not filled out).

As Make.com newcomers, we have tried various formulas using the available functions (merge, if, toArray, emptyarray) to build this array, but we consistently encounter errors like:

Function ‘…’ not found (syntax issues or unavailable functions)

Invalid URL in parameter ‘url’ (which we believe happens when the Iterator passes an empty value to the HTTP module).

Our Question:

We need to avoid creating multiple scenario branches. What is the most reliable and idiomatic (accepted Make.com) way to construct a clean array of URL strings in the Array field of the Iterator module, ensuring that it safely excludes empty/null values?

We kindly ask for guidance on the correct combination of the available functions (merge(), if(), toArray(), etc.) to build this conditional array of URLs.

I am attaching two sample Webhook Outputs (Payloads) for scenarios with 2 and 4 valid links to help you reproduce the data structure.

Thank you so much for your assistance, patience, and time!

Sincerely, Alex

2URL(to jpg,png,pdf in cloud service)

[

{

    "directorPassportLegalUrl": "https://res.cloudinary.com/doh1kpb2s/image/upload/v1763484973/vbvombafwykdjcgqehx6.pdf",

    "techPassportFrontLegalUrl": "https://res.cloudinary.com/doh1kpb2s/image/upload/v1763484973/rlifvfyyxxxwipybzijs.pdf",

    "insuranceTermLegal": "6",

    "startDateLegal": "0011-11-11",

    "regNumber": "123213123231",

    "contactFullName": "aleks_dundolk",

    "contactEmail": "aleks_dundolk@gmail.com",

    "contactPhone": "2343223456567",

    "entityType": "Юридическое Л."

}

]

4URL(to jpg,png,pdf in cloud service)

[

{

    "techPassportBackLegalUrl": "https://res.cloudinary.com/doh1kpb2s/image/upload/v1763485090/gdutb7c1wwgak6hywdon.pdf",

    "techPassportFrontLegalUrl": "https://res.cloudinary.com/doh1kpb2s/image/upload/v1763485090/xjbka2jjg1geptk3gjqt.pdf",

    "directorPassportLegalUrl": "https://res.cloudinary.com/doh1kpb2s/image/upload/v1763485090/eevm0sqss5htraitb2nf.jpg",

    "directorPassportLegalBackUrl": "https://res.cloudinary.com/doh1kpb2s/image/upload/v1763485091/ypmsiaygoqfrqww3pgec.pdf",

    "insuranceTermLegal": "12",

    "startDateLegal": "0011-11-11",

    "regNumber": "QWER2443DF77",

    "contactFullName": "andrej_vitol",

    "contactEmail": "andrej_vitol@yahoo.com",

    "contactPhone": "34467988889",

    "entityType": "Юридическое Л."

}

]

Hello again @Andrejs - see attached sample:

I made a sample with two different versions/routes - one that downloads the files and sends them as data, and one that just sends the URLs directly. For your use case here I’d recommend just using the URL route because it’s the simplest and Brevo supports URLs.

But, I’m including the instructions for direct data download as well in case you switch from Brevo to something that doesn’t support URLs, or if Brevo’s URL won’t support all file types you need (I tested only with images and PDFs):

1. With Direct Data Download (top route)

  1. Iterator: we can’t use merge here because your files are now no longer arrays, so we create an array from scratch using add() formula. To an emptyarray, we add all your file variables (add all 8)

  2. Filter: after the iterator, add the filter that checks whether value exists - the URL itself:

  3. Then add your HTTP module - Get a File, and map value from the iterator to it. This will download the file from the URL

  4. Add another filter after HTTP module - just in case the download didn’t go through:

    Extra details: Error handling with this HTTP module

    It depends how you want to handle failed downloads, really. If you turn on “advanced” settings in HTTP module and enable “evaluate all states as errors”, it means this module will fail and effectively stop your scenario’s/webhook’s processing if a file fails to download:

    If you want this to “silently” fail, you can add the filter above from step 4. Alternatively, you can add error handlers to this module to handle failed downloads differently.

  5. Array aggregator - while this is mostly as simple as the previous solution was, you did now lose the original filename of the attachments because Cloudinary only sends a URL. So for the file name, I added a switch() formula that lets you set the file name manually.

    Source module: Iterator
    Target structure type: Brevo attachments
    Attachments > type: Data
    File: switch this to manual mapping**

    Name:** uses switch() formula to set a different name based on matching the URL to the original variables.
    Uses -timestamp suffix to ensure unique filenames.
    Fallback is file-timestamp.
    Extracts file extension from URL using last(split()) formulas.

    Data: just map the data output from HTTP module.

Switch-case formula example (it’s like a nested if but more elegant for comparing to one static value like the URL in your case):

{{switch(2.value; 
1.techPassportBackLegalUrl; "Tech Passport Back"; 
1.techPassportFrontLegalUrl; "Tech Passport Front"; 
1.directorPassportLegalUrl; "Director Passport Front"; 1.directorPassportLegalBackUrl; "Director Passport Back"; 
"file")}}-{{timestamp}}.{{last(split(2.value; "."))}}

  1. And then Brevo at the end as before, just map the output of Array Aggregator to the attachments field

2. With URL (bottom route)

Much simpler solution, just pass URLs directly to Brevo attachments fields:

  1. Iterator: same as above, add all URLs to an array

  2. Filter: same as above, filter out empty fields

  3. Array aggregator:
    Attachments > Type: URL
    File name: same switch formula from above
    Image URL: map the value from the iterator

    (I know this says “image” URL but I tested it with a PDF and it worked just fine)

  4. Brevo - same as above, map the output of the aggregator to Brevo’s attachments array

Cheers,
Sierra

1 Like

Thank you, Sierra! I was able to quickly apply your advice, and now this complex Iterator/HTTP/Aggregator cycle finally works as it should. Your answers are, as always, outstanding — thank you!

1 Like