Zum Hauptinhalt springen

FromEmailNodeConfiguration

Namespace: Meshmakers.Octo.MeshAdapter.Nodes.Trigger

Configuration for node FromEmail

public record FromEmailNodeConfiguration : TriggerNodeConfiguration, INodeConfiguration, IEquatable<NodeConfiguration>, ITriggerNodeConfiguration, IEquatable<TriggerNodeConfiguration>, IEquatable<FromEmailNodeConfiguration>

Inheritance Object → NodeConfiguration → TriggerNodeConfiguration → FromEmailNodeConfiguration
Implements INodeConfiguration, IEquatable<NodeConfiguration>, ITriggerNodeConfiguration, IEquatable<TriggerNodeConfiguration>, IEquatable<FromEmailNodeConfiguration>

Fields​

DefaultMaxMessagesPerPoll​

Default for FromEmailNodeConfiguration.MaxMessagesPerPoll, resolved where the value is read.

public static int DefaultMaxMessagesPerPoll;

Properties​

ServerConfiguration​

The global configuration key for the email server settings

public string ServerConfiguration { get; set; }

Property Value​

String

PollingIntervalSeconds​

Polling interval in seconds to check for new emails

public int PollingIntervalSeconds { get; set; }

Property Value​

Int32

MaxMessagesPerPoll​

Maximum number of messages fetched and dispatched in a single polling pass (AB#5336). Each message is downloaded in full and its attachments are base64-encoded into the batch, so an unbounded result set is an out-of-memory failure on any mailbox with history. A backlog is drained over consecutive polls instead. Values <= 0 mean "no limit" and are not recommended.

Nullable with the default resolved at the call site on purpose: the pipeline definition deserializer is YamlDotNet, where a key that is PRESENT and null overwrites a property initializer. On a non-nullable int that yields 0 — which this node reads as the deliberate "no limit" opt-out, so an explicit null would silently switch the OOM protection back off.

public Nullable<int> MaxMessagesPerPoll { get; set; }

Property Value​

Nullable<Int32>

OnlyUnread​

Whether to only process unread emails

public bool OnlyUnread { get; set; }

Property Value​

Boolean

MarkAsRead​

Whether to mark emails as read after a CONFIRMED import.

public bool MarkAsRead { get; set; }

Property Value​

Boolean

Remarks:

Superseded by FromEmailNodeConfiguration.PostProcessingMode (AB#5345) and read only while no mode is set, where it derives MailPostProcessingMode.MarkAsRead. Kept — rather than removed — because every deployed FromEmail@1 names it, and a property a released node stops honouring turns other tenants' pipelines into silent behaviour changes.

DeleteAfterProcessing​

Whether to delete emails after a CONFIRMED import.

public bool DeleteAfterProcessing { get; set; }

Property Value​

Boolean

Remarks:

Superseded by FromEmailNodeConfiguration.PostProcessingMode (AB#5345) and read only while no mode is set, where it derives MailPostProcessingMode.Delete and wins over FromEmailNodeConfiguration.MarkAsRead.

SuccessPath​

Path into the pipeline's result data that CONFIRMS the batch was imported (AB#5337). \Seen / \Deleted are written back only when it resolves to the boolean true; anything else — absent, null, false, a string, a number — leaves the mails exactly as the server has them, so a later restart offers them again.

🔴 Why this exists: a pipeline can end perfectly normally while a node reported an error and stopped its branch — that is what MakeHttpRequest@1's LogAndStop is defined to do ("leaving the execution successful") — and the platform surfaces no per-node status to a trigger: the execution status is Completed unless something threw, and ExecuteAsync returns the pipeline's data root, nothing else. Without a confirmation the trigger cannot see such a branch, so this is the only way to make the write-back conditional on the import itself.

⚠️ UNSET keeps the pre-AB#5337 behaviour: a run that came back flags its mails. A stricter default would stop every deployed FromEmail@1 from marking anything read and re-offer its whole SINCE window on every adapter restart — a certain fleet-wide regression traded for one edge case. What is NEVER traded is the run that threw: that one leaves the mailbox untouched whatever this is set to.

AB#5345 built on exactly this hook: the flag the pipeline writes here is now the BUSINESS success criterion — "at least one inbox item was created" — and it gates every one of the three FromEmailNodeConfiguration.PostProcessingModes, on this channel and on the Microsoft Graph one. The evaluation itself moved to MailSuccessPath, which both triggers share.

Write the flag as the LAST step of the import branch (e.g. SetPrimitiveValue@1 targetPath: $.importCompleted, value: true, valueType: Boolean) — placed there, a branch that stopped early never reaches it.

Syntax: a plain path from the pipeline data root, optionally with the $. prefix ($.importCompleted, result.ok). Array indexes, wildcards and filters are rejected when the trigger starts — a confirmation must name exactly one value.

public string SuccessPath { get; set; }

Property Value​

String

SenderFilter​

Optional filter for sender email address (contains match)

public string SenderFilter { get; set; }

Property Value​

String

SubjectFilter​

Optional filter for email subject (contains match)

public string SubjectFilter { get; set; }

Property Value​

String

SinceDate​

Only consider messages delivered on or after this date (AB#5340). Maps to the IMAP SINCE key, which the server evaluates on the message's INTERNALDATE with date granularity and inclusive bounds. Takes precedence over FromEmailNodeConfiguration.SinceDaysBack.

public Nullable<DateTime> SinceDate { get; set; }

Property Value​

Nullable<DateTime>

SinceDaysBack​

Only consider messages delivered within the last N days (AB#5340). Relative alternative to FromEmailNodeConfiguration.SinceDate, which wins when both are configured. Values <= 0 are ignored.

public Nullable<int> SinceDaysBack { get; set; }

Property Value​

Nullable<Int32>

WindowOpen​

Whether this trigger currently has an import window at all (AB#5341). false means the window is EMPTY and the trigger fetches nothing: it skips the whole polling pass — no search, no download, no pipeline run — and picks up again by itself as soon as the value flips back.

This exists because "no cut-off" cannot express "import nothing". An absent FromEmailNodeConfiguration.SinceDate / FromEmailNodeConfiguration.SinceDaysBack means "no date filter", which with FromEmailNodeConfiguration.OnlyUnread switched off is the unbounded SearchQuery.All that killed the adapter on prod-1 with 1697 mails (AB#5336) — the exact opposite of what an empty window has to do. The accounting channel derives both values from the OPEN fiscal years, and "no fiscal year is open" has to mean nothing is imported, not everything.

Deliberately NOT the operator's System/Enabled switch: that one is owned by whoever configures the channel, and flipping it from a computation would both fight the operator and require a DATA FLOW deploy to take effect (a disabled pipeline is dropped by DeployDataFlow), which restarts every sibling trigger. This value rides on the settings configuration instead, so a single-pipeline DeployPipeline@1 delivers it.

Nullable with the default resolved at the call site, for the YamlDotNet reason documented on FromEmailNodeConfiguration.MaxMessagesPerPoll: a key that is PRESENT and null overwrites a property initializer, and on a non-nullable bool that yields false — which would silently switch a working mailbox off. Unset therefore reads as OPEN; see FromEmailNode.ResolveWindowOpen.

public Nullable<bool> WindowOpen { get; set; }

Property Value​

Nullable<Boolean>

PostProcessingMode​

Post-processing applied to a message once its pipeline run confirmed the import (AB#5345) — the same three modes the Microsoft Graph channel offers, so a settings page can present ONE choice for both. Overrides FromEmailNodeConfiguration.MarkAsRead / FromEmailNodeConfiguration.DeleteAfterProcessing when set.

⚠️ UNSET is the migration path and means "keep doing what this pipeline already did": the mode is then DERIVED from the two legacy flags — FromEmailNodeConfiguration.DeleteAfterProcessing ⇒ MailPostProcessingMode.Delete, else FromEmailNodeConfiguration.MarkAsRead ⇒ MailPostProcessingMode.MarkAsRead. Both flags on is not a lost combination: a deleted message is expunged, so the \Seen flag it would also have carried is not observable by anyone.

🔴 There is no fourth mode that leaves the message alone, and neither flag set is a configuration error rather than a mode (AB#5372): the trigger start FAILS naming the three valid modes. None = 0 existed until then and was a defect. Nothing in OctoMesh records which mail was already processed — the mailbox IS the bookkeeping, the IMAP search is NotSeen, and the three modes work precisely because each takes the message out of that search result. Leaving it in re-fetches the same FromEmailNodeConfiguration.MaxMessagesPerPoll messages on every poll and never reaches the mail behind the cap, so the import runs for ever, reports success and imports nothing new — the shape of AB#5336.

Still nullable and still only read through ResolveEffectivePostProcessingMode, never directly: the pipeline definition deserializer is YamlDotNet, where a key that is PRESENT and null overwrites a property initializer. On a non-nullable enum that would yield the zero value, which is now no member at all; nullable, such a key reads as "unset" and the derivation above decides — the same answer a pipeline that omits the key gets.

public Nullable<MailPostProcessingMode> PostProcessingMode { get; set; }

Property Value​

Nullable<MailPostProcessingMode>

SourceFolder​

Folder polled as the work queue, overriding the Folder of the FromEmailNodeConfiguration.ServerConfiguration entity when set. Optional: the connection entity is still the place a plain single-folder import configures its folder; this exists because MailPostProcessingMode.MoveToFolders needs a source folder that belongs to the same triple as FromEmailNodeConfiguration.DoneFolder and FromEmailNodeConfiguration.FailedFolder.

public string SourceFolder { get; set; }

Property Value​

String

DoneFolder​

Folder a message is moved to once its import was confirmed, under MailPostProcessingMode.MoveToFolders. Segments separated by / and translated to the server's own hierarchy delimiter — the leaf is created when missing, its parents must exist.

public string DoneFolder { get; set; }

Property Value​

String

FailedFolder​

Folder a message is moved to when its import was NOT confirmed, under MailPostProcessingMode.MoveToFolders. Left empty, such a message stays in the source folder.

Set it wherever the import matters: it is not only where a mail nobody could import is parked, it is also the way BACK — moving a message from here into the source folder offers it to the import again. Unlike the Graph channel this trigger does NOT count attempts per message (there is no IMAP counterpart to an Outlook category that survives a process death, and the IMAP batch is one execution for many messages rather than one per message), so a message whose batch was not confirmed is moved aside on that first unconfirmed run.

public string FailedFolder { get; set; }

Property Value​

String

SettingsConfiguration​

Optional well-known name of a configuration entity carrying the RUNTIME settings of this trigger, so they live in configuration instead of the pipeline definition (AB#5345). The configuration must be reachable from the pipeline through a System.Communication/Uses association.

🔴 The rule this exists for: setting a setting must never rewrite a pipeline definition. The definition is release content — it is what a redeploy reinstates — while a poll interval or an "only unread" switch is operating state. Writing the latter into the former is how the accounting app moved one tenant's pipeline entity from v35 to v39 with nothing but a checkbox.

The node stays domain-agnostic: which attributes to read is given by the *Attribute properties below. A value found there overrides the corresponding node property; anything missing falls back to the node property, which is what keeps every already deployed pipeline behaving exactly as before.

public string SettingsConfiguration { get; set; }

Property Value​

String

PollingSecondsAttribute​

Attribute holding the poll interval in seconds (positive integers only).

public string PollingSecondsAttribute { get; set; }

Property Value​

String

OnlyUnreadAttribute​

Attribute holding the "only unread" switch (FromEmailNodeConfiguration.OnlyUnread).

public string OnlyUnreadAttribute { get; set; }

Property Value​

String

PostProcessingModeAttribute​

Attribute holding the post-processing mode NAME (MailPostProcessingMode). Names only — a number there is ignored, see ConfigurationSettingsReader.ReadEnum.

⚠️ An unknown name means "not configured" and hands the decision back to FromEmailNodeConfiguration.PostProcessingMode — with ONE exception: a stored None FAILS the trigger start (AB#5372). It was a real, storable mode until then, so reading it as "not configured" would silently replace an operator's "change nothing" with the derived mode and start writing to their mailbox.

public string PostProcessingModeAttribute { get; set; }

Property Value​

String

SourceFolderAttribute​

Attribute holding the polled folder (FromEmailNodeConfiguration.SourceFolder).

public string SourceFolderAttribute { get; set; }

Property Value​

String

DoneFolderAttribute​

Attribute holding the done folder (FromEmailNodeConfiguration.DoneFolder).

public string DoneFolderAttribute { get; set; }

Property Value​

String

FailedFolderAttribute​

Attribute holding the failed folder (FromEmailNodeConfiguration.FailedFolder).

public string FailedFolderAttribute { get; set; }

Property Value​

String

MaxMessagesPerPollAttribute​

Attribute holding the per-poll batch cap (FromEmailNodeConfiguration.MaxMessagesPerPoll). Read with the zero-tolerant integer reader, because a configured 0 is this property's deliberate "no limit" opt-out rather than an unset value.

public string MaxMessagesPerPollAttribute { get; set; }

Property Value​

String

SinceDateAttribute​

Attribute holding the absolute date cut-off (FromEmailNodeConfiguration.SinceDate).

public string SinceDateAttribute { get; set; }

Property Value​

String

SinceDaysBackAttribute​

Attribute holding the relative date cut-off (FromEmailNodeConfiguration.SinceDaysBack).

public string SinceDaysBackAttribute { get; set; }

Property Value​

String

WindowOpenAttribute​

Attribute holding the import-window flag (FromEmailNodeConfiguration.WindowOpen). A false there suspends fetching for as long as it stands; unset leaves the definition's value, which is "open".

public string WindowOpenAttribute { get; set; }

Property Value​

String

SenderFilterAttribute​

Attribute holding the sender filter (FromEmailNodeConfiguration.SenderFilter).

public string SenderFilterAttribute { get; set; }

Property Value​

String

SubjectFilterAttribute​

Attribute holding the subject filter (FromEmailNodeConfiguration.SubjectFilter).

public string SubjectFilterAttribute { get; set; }

Property Value​

String

SuccessPathAttribute​

Attribute holding the import confirmation path (FromEmailNodeConfiguration.SuccessPath). Rarely worth configuring — the path is a contract between this trigger and the pipeline it starts, both of which ship together — but it is a setting like the others and behaves like them.

public string SuccessPathAttribute { get; set; }

Property Value​

String

CallerBinding​

public CallerBindingMode CallerBinding { get; set; }

Property Value​

CallerBindingMode

Description​

public string Description { get; set; }

Property Value​

String

Constructors​

FromEmailNodeConfiguration()​

public FromEmailNodeConfiguration()