Exclude subscribers who received specific campaign(s)

ele

Member
I encounter a use case on which I'm not sure how to manage it from the MailWizz context. Well, what I want is to be able to exclude the persons who previously received certain campaigns (e.g., sending C10, I want to exclude those who received C2 and C5; "C" for "campaign", of course).

Ideally, the way I'm managing my emailing environment is to have just one list per activity (being software author, it means per app, for example). I don't want to have multiple lists with all the complexity of duplicates, syncing, etc. Just one list and a hashtag list in a custom field (I called "Tags"; it could be "Hashtags") to produce my segments (of course, these hashtags are informed correctly)...

Then, following this type of management, the most logical would be to add a custom field called "Campaigns", then add the names or UID's of the received campaigns in this field. In the campaign setup, we can change the value of a custom field after sending of a campaign, but we can't add a value in this field. We can just overwrite it, while I would need to be able to do something like what is shown below. Here is my issue!

snap_2025-04-25_11-37-43.png

So, I searched an alternative... For example, I see I can exclude subscribers who opened or didn't open a previous campaign(s) (see screenshot below), but not who received it/them (i.e., doesn't matter if they opened or not).

snap_2025-04-25_12-00-53.png

Another option would be to manage this from the definition of a segment where I can indicate campaigns-related condition (see capture below), but again it's about open and click only; not sending/receiving; and I can select one condition only (not both "open AND not open").

snap_2025-04-25_12-05-56.png

I could also manage this by myself through the API (updating the concerned field) after the campaign is sent to a subscriber relying on webhook event, but there's only event on email opening, not sending (see screenshot below).

1745578769563.png

So, what? For me, the easiest way would be to manage this as expressed at the beginning of this post... So, it would require to have a placeholder/variable about current value of a custom field (e.g., "Campaigns") doing I would be able to enter something like "[CURRENT_VALUE] [CAMPAIGN_UID]" to concatenate both values (where [CURRENT_VALUE] returns the list of the previous campaigns already added in this field for the concerned person).

Unless you have an easier way in mind I could have missed...
 
Last edited:
OK, searching the forum, I found this post, then adjusted for my need ;) Here is the result (the campaign name is added in a CAMPAIGNS field after an email is sent to the subscriber). Just take care to create the custom field as textarea to avoid the limit of 255 characters in a text/string field. And, of course, after this, never change the name of your campaigns LOL

Code:
// Updates subscriber's CAMPAIGNS field when a campaign is sent
Yii::app()->hooks->addAction('console_command_send_campaigns_after_send_to_subscriber', function($campaign, $subscriber, $customer, $server, $sent, $response, $status) {
  
    $subscriberId = $subscriber->subscriber_id;

    if (!$sent) {
        return; // email not sent
    }

    // Get current value
    $fieldTag = 'CAMPAIGNS';
    $field = ListField::model()->findByAttributes(['tag' => $fieldTag]);
    if (!$field) {
        return; // custom field not found
    }

    $fieldId = $field->field_id;

    $subscriberField = ListFieldValue::model()->findByAttributes([
        'field_id' => $fieldId,
        'subscriber_id' => $subscriberId,
    ]);
    $value = $subscriberField ? $subscriberField->value : '';

    // Append campaign name
    $campaignName = $campaign->name;
    $newValue = $value ? $value . " '" . $campaignName . "'" : "'" . $campaignName . "'";

    // Update field or create a new record in custom fields table if missing
    if ($subscriberField) {
        $subscriberField->value = $newValue;
        $subscriberField->save(false); // no validation
    } else {
        $newFieldValue = new ListFieldValue();
        $newFieldValue->field_id = $fieldId;
        $newFieldValue->subscriber_id = $subscriberId;
        $newFieldValue->value = $newValue;
        $newFieldValue->save(false); // Save as a new entry
    }
});

--
EDIT (some hours later): Damnation! I see that even textarea is limited to 255 characters °O° Well, well...
 
Last edited:
Added this hook (as per this post) and changed the type accordingly in the database, but the limit remains in the UI... Do you know how to go further?

Code:
hooks()->addFilter('listfieldvalue_model_value_max_length', function($length){
    return 1024;
});

snap_2025-04-26_15-15-52.png
 
Last edited:
Well, I saw that the issue is that all the custom field values are stored in the same column whatever the chosen type of a custom field at UI level. So, text field or textarea field is treated the same way in the 'mw_list_field_value' table.

1745755037178.png

So, of course, it could be allowed to increase the max length limit in the code accordingly to a change of the type of the 'value' column in the database itself, but this could (depending on the said limit; VARCHAR(1000) != VARCHAR(32768) != TEXT != LONGTEXT) impact the overall performance in speed... At the end, this lack of differentiation does that there's an issue of alignment between the UI and the underlying database: the difference between a text and texarea is just about the control, the look and feel, but not the capacity... Thus, maybe this point could be added as a feature request (here, you have two solutions: 1. you can create a dedicated column for textarea values in the same table, this is the quickest even if not a clean design (e.g., waste with empty field assured in each record), 2. you store the textarea value in a separate table, this will complicate the queries, but it's cleaner from the schema's point of view)...

On my side, about my specific use case, I finally solved this this way: I kept the VARCHAR(255) limit and shorten the campaign name through a convention of abbreviations (now, I can express every campaign by a maximum of 5 chars, separators included, then I have room for a history of ~50 campaigns; and if it overflows a day -- before the db schema upgrade I mean (wink) -- I'll just create a new custom field called CAMPAIGNS2 -- this will enlarge the segment definitions, but nothing insurmountable) which can be deduced by my hook from the full campaign name.

"Solved!"
 
Last edited:
Back
Top