I want to explain to our client where the numbers from the SPAM complaints come from.
But I actually don't know how this gets tracked or functions.

Each email campaign report shows a bunch of different statistics. And Spam complaints is one of them: Spam complaints

Is it the mail client itself that sends a message back, hey your email is spam? It's not when a user himself marks an email as spam?

So, how does SC know when a mail was marked as spam by its receiver?


What @steve-mcgill said is completely correct, but I can offer a bit of background on the implementation.

Assuming EXM 3.3/4/+:

In the file


where XXX is the provider (Dyn/SparkPost), there are a number of agents. One of them, the


pulls complaints from the provider at a configurable interval. You can configure how often it runs, and how many complaints it should request at once.

These (spam) complaints will not be processed at once, as that could potentially have a negative impact on the performance of your CM server(s). Instead, EXM creates tasks in the Tasks table of the exm.master database.

In the same configuration file, the

<complaintsTaskProcessor type="Sitecore.EDS.Providers.SparkPost.Tasks.ComplaintsTaskProcessor, Sitecore.EDS.Providers.SparkPost">

is responsible for actually processing the complaints. The

<complaintsTaskAgent type="Sitecore.ExM.Framework.Distributed.Tasks.Processing.ShortRunning.DatabaseTaskAgent,Sitecore.ExM.Framework" singleInstance="true">

is used to configure how the tasks are processed. There are a number of configuration options (warning, wall of text incoming. TL;DR below):

  • taskPool is a reference to the task pool to execute tasks from.
  • targetMinBufferAmount The agent will attempt to adjust the amount of tasks retrieved from the pool so a small amount of unprocessed tasks remain at the end of each iteration. This is to prevent the processors from running out of work during the iteration in case there are variations in the processing speed. This parameter defines the minimum number of tasks it will attempt to have remaining. It should be set to a number of tasks that one thread would be able to process during one iteration with time to spare during normal operation.
  • maxBatchSize The largest number of tasks the agent can request in each iteration. This number should be higher than the number of tasks expected to be processed per iteration during normal operation.
  • idleIterationDuration The length of an iteration when the agent is idling. The agent will idle if no work is available.
  • activeIterationDuration The length of an iteration when the agent is processing tasks. This should be longer than the expected time to process a task during normal operation.
  • leaseTime The amount of time a task is reserved by the agent when retrievede from the task pool. A task is reserved for a limited amount of time so it will be available for other agents to process after a while in case the agent that reserved it crashes before it has finished the task. It is recommended not to set this lease time shoter than the connection timeout of the task pool's database connection.
  • postponeTime A processor can choose to postpone a task in which case it will be returned to the task pool and scheduled for later processing. This is the amount of time a task will be postponed.
  • maxDegreeOfParallelism The maximum number of threads the agent can use for processing tasks.
  • maxFailedProcessingAttempts If the user-defiend processor throws an unhandled exception while processing a task the task will be returned to the pool and retried later. After the number of failed attempts to process a task defined by this setting the task will be considered invalid and removed from the pool.
  • processor A reference to a user-defined class which will be invoked for every task to process. The class must extend the abstract class Sitecore.ExM.Framework.Distributed.Tasks.Processing.ShortRunning.TaskProcessor.

I do not suggest changing the default parameters unless you know what you are doing ;) TL;DR It allows EXM to throttle and retry tasks.

For each task processed by the task processor, the


fires off the handleSpamComplaint pipeline.

In EXM 3.4+ the handleSpamComplaint pipeline is split up into three pipelines:

  • exm.recipientListManagement.add (adds the contact to the global opt out list)
  • exm.recipientListManagement.remove (removes the contact from the list(s) they were included in - note, it cannot remove contacts from segmented lists)

In EXM 3.3 these actions were done directly in the handleSpamComplaint pipeline.

In addition to this, the handleSpamComplaint pipeline creates an Interaction in xDB, which is what EXM is using to generate the reports you're asking about.


Every email service which receives email will have a different mechanism of reporting spam complaints to the ISP responsible for sending emails. The Sitecore Email Cloud entrusts our email provider to reach agreements with the various services such as Microsoft, Google, Yahoo, etc, to capture this data.

EXM then polls this information at regular intervals so that it can be included in the reporting dashboard.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.