> For the complete documentation index, see [llms.txt](https://docs.openiam.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.openiam.com/administration-guide/requests/fulfilment.md).

# Manual fulfilment

Route access in a system OpenIAM cannot provision to a human fulfiller — the Manual flag, the manualTask process, who it is assigned to, what the fulfiller sees, and how completion is recorded.

## What this is, and when you need it

Some targets have no connector: a badge system, a physical key cabinet, a mainframe reached by a terminal, a vendor portal with no API. OpenIAM handles those by marking the managed system **Manual**, which changes its resource type, which makes an approved request produce a **human task** instead of a provisioning call. The person who receives that task does the work in the managed system and clicks **Complete**.

Manual fulfilment is not an approval step. Approval decides *whether* access is granted; manual fulfilment happens *after* the decision and records *that the work was done*. It also has nothing to do with **Manual Reconciliation**, which is a reconciliation option on a managed system — `openiam.ui.reconciliation.manual.recon.not.allowed` refers to that, not to this.

## At a glance

|                          |                                                                                                                                                                                      |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **You will end up with** | An approved request for a connector-less application producing a **Manual Task** in a named fulfiller's inbox, and the `PENDING_MANUAL_ASSIGNMENT` tag cleared when they complete it |
| **Where**                | **Provisioning → Managed System** (`/webconsole/mngsystem`) for the **Manual** flag; the resource's access rights for the fulfiller; **SelfService → Inbox** for the task itself     |
| **You need first**       | A managed system whose target has no usable connector; one user or one group to fulfil for it; mail configured if you want them notified                                             |
| **Takes**                | 20 to 30 minutes, plus one test request approved end to end                                                                                                                          |
| **Reversible**           | Partly. Clearing **Manual** and re-saving restores provisioning, but tasks already in flight keep their candidates and must be completed or cancelled by hand                        |

## Before you begin

* **A managed system whose target has no usable connector** — a badge system, a key cabinet, a mainframe reached by a terminal, a vendor portal with no API.
* **One user or one group to fulfil for it.** This is the **Admin Access** right on the managed system's resource, *not* an approver association. With no such right granted, every manual task falls back to `org.openiam.idm.activiti.default.approver.user`, which ships as `3000` — `sysadmin`.
* **Mail configured**, if you want the fulfiller notified — see [Mail and notifications](/administration-guide/platform/mail-and-notifications.md).
* **An accepted control consequence.** An entitlement in flight through a manual task is **tagged and excluded** from certification and from risk scoring for as long as the task is open. If that is unacceptable in your controls, do not use manual fulfilment for that entitlement. The detail is under [What completion actually records](#what-completion-actually-records).

{% hint style="danger" %}
**Never reject a manual task; cancel the request instead.** A manual task that ends with any status other than `COMPLETED` leaves the entitlement in limbo: the completion step never runs, the `PENDING_MANUAL_ASSIGNMENT` tag is never removed, and the entitlement stays hidden from certification and risk indefinitely. SelfService protects you by offering **Complete** and no **Reject**; a decision made in bulk, or an "I reject this request" email reply, is not similarly constrained, and neither is an integration built against OpenIAM's API by your own developers.
{% endhint %}

## Configure manual fulfilment

{% stepper %}
{% step %}

### Create the managed system with **Manual** set

**Provisioning → Managed System → New**, at `/webconsole/mngsystem`. Set **Name**, tick **Manual**, leave **Connector** empty — `CONNECTOR_REQUIRED` is not raised for a manual system — and leave **Active** off until you have finished. Save.
{% endstep %}

{% step %}

### Confirm the resource type

Reopen the managed system and confirm its resource is type `MAN_MANAGED_SYS`, displayed as *Manual Managed Systems*. This is the actual switch; if the resource is still `MANAGED_SYS`, approved requests will not produce a task.
{% endstep %}

{% step %}

### Nominate the fulfiller with the `ADMIN` right

Grant the **Admin Access** right — the `ACCESS_RIGHTS` row `ADMIN` — on that resource to one user or one group. A user gets the task assigned; a group's members each get a candidate task they must claim. Prefer a group of at least two people — a single named fulfiller is a single point of failure for every request against that application.
{% endstep %}

{% step %}

### Put the application in the request catalog

Set the managed system's **Application category** so it appears in SelfService, and link the roles or groups people will request to its resource. See [The request catalog and questionnaires](/administration-guide/requests/request-catalog.md).
{% endstep %}

{% step %}

### Set the approval separately

Manual fulfilment does not replace approval. Configure the approver associations for the request type as usual — see [Approval flows](/administration-guide/requests/approval-flows.md) — and remember that the shipped default is user `3000`.
{% endstep %}

{% step %}

### Test with one disposable request

Raise one request as a test user, approve it, and confirm a **Manual Task** appears for the fulfiller. Complete it, and confirm the tag is gone. Then set the managed system **Active**.
{% endstep %}
{% endstepper %}

## Verification

One test request should produce all of:

1. A `MANUAL_TASK` audit record, source `WORKFLOW`, whose request ID starts with `M`, with the target task ID and name set.
2. A child info line on the approval's audit record: `Initiating manual task to assign access in manual managed system <resource>.`
3. A `TASK_LISTENER` record carrying the `CANDIDATE_USER_IDS` attribute — compare it with who you granted the `ADMIN` right to. If it contains `3000`, the right is not granted where you think it is.
4. A task named **Manual Task** in the fulfiller's **SelfService → Inbox**, showing only a **Complete** button, with the instruction text in *Reason for Request*.
5. The requested role or group present on the user and carrying the tag *Pending manual assignment* (`PENDING_MANUAL_ASSIGNMENT`).
6. After **Complete**: a `MAKE_DECISION` audit record, `STATUS = COMPLETED` on the process, the tag **gone** from the membership, and notifications to the target user and the requester.
7. For an email response: `MAKE_DECISION_FROM_EMAIL` with `Request ID` and `Response` populated, and a reply in the responder's mailbox reading `Action APPROVE successfully performed on task <requestId>`.

## When it goes wrong

| Symptom                                                                      | Cause to check                                                                                                                              | Fix                                                                                                                                |
| ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| Approved request granted access without a task                               | The target resource's type is `MANAGED_SYS`, not `MAN_MANAGED_SYS`. Fulfilment tests the resource type, not the checkbox                    | Tick **Manual** and re-save the managed system, then reopen it and confirm the resource type                                       |
| Manual task created but assigned to `sysadmin`                               | No `ADMIN` right on the resource, or the admin group is empty, so it fell back to `org.openiam.idm.activiti.default.approver.user` (`3000`) | Grant **Admin Access** on the resource; also point that property at a monitored account                                            |
| No manual task at all, no error                                              | The request carried no target resource, so no fulfiller was resolved and no step was added                                                  | Check the `ResourceIds` variable on the request                                                                                    |
| Task visible to several people, nobody can complete it                       | More than one candidate resolved, so each was added as a candidate rather than one assigned                                                 | Claim it, or reduce the admin group to one member                                                                                  |
| Fulfiller sees **Approve**/**Reject** instead of **Complete**                | The task is not from the `manualTask` flow                                                                                                  | Check the `WorkflowName` variable; a manual task's `RequestId` starts with `M`                                                     |
| Someone rejected a manual task and the entitlement is stuck                  | The non-completed branch does nothing, so the completion step never ran and the tag stayed                                                  | Remove the tag by re-saving the membership, and cancel rather than reject in future                                                |
| Entitlement missing from a certification campaign                            | It still carries `PENDING_MANUAL_ASSIGNMENT`, so generation drops it and the preview reports `ENTITLEMENT_PENDING_MANUAL_ASSIGNMENT`        | Complete or cancel the manual task                                                                                                 |
| Fulfiller never notified                                                     | The notification comes from task assignment, is skipped for the requester, and goes through the custom notification script                  | Confirm the fulfiller is not also the requester; check `org.openiam.activiti.custom.notification.groovy.script` and the mail queue |
| Instruction text is wrong or in the wrong language                           | It is generated, not a mail template, and is not localizable                                                                                | No configuration changes it. Supply a description when the task is initiated, from a script                                        |
| Manual system reported as an unreachable connector                           | It should not be — connector health checks skip manual systems                                                                              | Confirm `MANAGED_SYS.IS_MANUAL_SYSTEM` is actually `Y`                                                                             |
| Manual system's policy map is empty after creation                           | No connector template is copied for a manual system                                                                                         | Expected; a manual system has nothing to map                                                                                       |
| Email replies do nothing                                                     | **Read Inbox?** is `N` on every mailbox configuration, so nothing is swept                                                                  | Turn it on, then wait one `org.openiam.email.inbox.sweep` interval (15 minutes)                                                    |
| Email replies do nothing, inbox is enabled                                   | The body does not contain the exact sentence, or the subject does not **end** with the request digits                                       | Do not let mail clients append text after the ID; check the audit reason `Email with subject … is not for automatic processing`    |
| Email reply rejected with a duplicate error                                  | `EMAIL_ADDRESS_DUPLICATED` — two users share that address; or `DUPLICATE_IDENTIFIER` — two tasks share the request ID                       | Deduplicate the email address; investigate the duplicate request ID                                                                |
| Inbox sweep logs `Can't read from Inbox-active Mailbox Configuration <name>` | The template has no IMAP host or no IMAP port                                                                                               | Set both on the **template**, not the configuration                                                                                |
| Inbox authentication fails                                                   | The sweep authenticates to IMAP with the configuration's **SMTP** username and password                                                     | Use a credential valid for both, or do not enable inbound processing                                                               |

## Roll it back

Clearing **Manual** on a managed system and re-saving changes its resource type back to `MANAGED_SYS`, after which approved requests provision instead of producing tasks. That does not resolve tasks already in flight: find open `manualTask` process instances in **SelfService → Request Management → Request Administration** (`/selfservice/request-administration`) and complete or cancel each one deliberately, then confirm no membership still carries `PENDING_MANUAL_ASSIGNMENT`. Removing the `ADMIN` right while tasks are open reassigns nothing — the candidates were resolved when the task was created.

## The `Manual` flag and its one real consequence

**Provisioning → Managed System → Manual** is a checkbox, stored as `MANAGED_SYS.IS_MANUAL_SYSTEM`, which ships `'N'` and has done since 4.0.0.0.

The consequence that matters is a **different resource type on the generated resource**. A managed system saved with **Manual** off produces a resource of type `MANAGED_SYS`; with **Manual** on, `MAN_MANAGED_SYS`, displayed as *Manual Managed Systems* and marked as not provisionable.

**`MAN_MANAGED_SYS` on the resource is what triggers manual fulfilment, not the checkbox.** At fulfilment time OpenIAM looks at the target resource's type, not at the flag. So the flag matters only because of the resource type it writes at save time — which is why step 2 of the procedure is "reopen the managed system and read the resource type", and why an old managed system that was never re-saved after the flag was ticked will keep provisioning silently.

Four other things follow from the flag:

| Behaviour                                         | What you will see                                                                                                                |
| ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| A connector is not required                       | Saving with an empty **Connector** succeeds. `CONNECTOR_REQUIRED` is raised only for a non-manual system                         |
| No policy map is copied from a connector template | The policy map is empty after creation, and that is correct — there is nothing to map                                            |
| Page-template attributes are not applied          | Attributes a connector template would normally seed are absent                                                                   |
| Connector health checks skip it                   | A manual system never appears as an unreachable connector, so its absence from a connector-health alert means nothing either way |

{% hint style="warning" %}
Turning the flag on for a system that already has a connector and a policy map does not delete them, but it does change the resource type on the next save — and from then on approved requests for that application produce manual tasks *instead of* provisioning calls. Turning it back off is symmetric. Test on a copy before changing it on a live managed system.
{% endhint %}

## How the `manualTask` flow differs from an approval

`manualTask` is one of the 49 shipped definitions ([Shipped approval workflows](/administration-guide/reference/shipped-workflows.md)), and its shape is deliberately unlike an approval flow. Four differences you can see from the request screens:

* **It is driven by a step count, not by an approver list.** The loop runs `CountOfApproverSteps` times rather than iterating `ApproverCardindality`.
* **Its exit condition is `STATUS == 'COMPLETED'`, not "was it approved".** Manual tasks are completed, not approved, and `IsTaskApproved` plays no part.
* **The user task is named `Manual Task`.** That name in **My Tasks** is how a fulfiller tells it apart from an approval, and its `RequestId` starts with `M`.
* **Nothing sends the fulfiller's notification on the flow's behalf.** The notification comes from the task assignment itself, which is why it is configured differently — see below.

After the task, the flow branches on the same condition: `COMPLETED` runs the completion step and ends; anything else does not.

{% hint style="danger" %}
The non-completed branch does nothing at all and has nowhere to go, which is why [you must never reject a manual task](#before-you-begin). You cannot see the damage from a screen — a process that ended on the dead branch looks like any other completed process, and the only visible trace is a membership still carrying the tag. So the check is on the **tag**, not on the process: after any manual task closes, confirm the tag is gone. Confirm the behaviour in your release before building automation that decides manual tasks.
{% endhint %}

## How a manual task is created

Three different events create a manual task. Knowing which one produced a task tells you what the fulfiller is being asked to do, and the task name says which it was:

| Trigger                    | When                                                                                                                          | Task name                                               | Requestor recorded               |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | -------------------------------- |
| An approved access request | The request was **approved** and its target resource's type is `MAN_MANAGED_SYS`                                              | `Provide access for <displayName> in <resource> system` | The real requester               |
| A revocation               | A revoke-access request, or a certification revoke decision, against a `MAN_MANAGED_SYS` resource                             | `Revoke access for <displayName> in <resource> system`  | `3000` on the revoke-access path |
| A termination              | A terminated user holds roles or groups whose resources include a `MAN_MANAGED_SYS` resource — **one task per such resource** | `Terminate user <displayName> in <resource> system`     | `0001`                           |

Before starting the process, OpenIAM validates the target user, then **tags every in-flight entitlement** with `PENDING_MANUAL_ASSIGNMENT` and saves those memberships, then resolves the fulfillers and starts the process.

That tagging save is asynchronous, so on a busy system there is a short window in which the task exists and the tag is not yet visible on the user. Do not conclude the tagging failed from a single refresh.

The audit action for the whole operation is **`MANUAL_TASK`**, source `WORKFLOW`, and the audit record's request ID is the original request ID prefixed with `M`. The approval's own audit record also carries a child line reading `Initiating manual task to assign access in manual managed system <resource>.` — search that string when you need to prove the handover happened. The termination path additionally audits `INITIATE_MANUAL_TASKS_FOR_TERMINATION` around its loop, once, however many tasks it created.

### The variables the process starts with

Worth having, because these are what you read on a stuck manual task ([Enumerated values](/administration-guide/reference/enums.md#workflow-variables) for the full set):

| Variable                      | Value at start                                                                     |
| ----------------------------- | ---------------------------------------------------------------------------------- |
| `STATUS`                      | `TODO`                                                                             |
| `WorkflowName`                | `manualTask`                                                                       |
| `RequestId`                   | `"M"` + the request ID — the leading `M` is how a manual task's ID is recognisable |
| `TaskName`, `TaskDescription` | The task name from the table above                                                 |
| `UserNotes`                   | The instruction text — see the next section                                        |
| `AssociationId`               | The **target user's** ID                                                           |
| `Requestor`                   | The requester's user ID                                                            |
| `ApproverCardindality`        | `<userId>:<level>` for each resolved fulfiller                                     |
| `ApproverLevel`               | `"0"`, or `"-1"` if no steps were resolved                                         |
| `CountOfApproverSteps`        | Drives `loopCardinality`                                                           |
| `ResourceIds`                 | The target resource ID, when set                                                   |
| `Questionnaire`               | Carried over from the original request                                             |
| `AuditLogId`                  | The `MANUAL_TASK` audit record, so children link to it                             |

Comments and attachments from the parent request are copied onto the new process instance, so the fulfiller sees the approval conversation rather than a bare instruction.

## How the task is assigned

**Not** by approver associations. OpenIAM reads the **target resource's Admin**, in four hops:

### 1. It loads the target resource

If the request carried no target resource, **no fulfiller is resolved and nothing is reported** — you get a process instance with no task in it. Check the `ResourceIds` variable on the request when a manual task simply never appears.

### 2. It reads the resource's Admin

The resource's Admin is either a user or a group. OpenIAM looks first for a **user** holding the admin access right on that resource and, only if no user matched, for a **group** holding the same right. The right in question is named by `org.openiam.ui.admin.right.id`, shipped **`ADMIN`** — the `ACCESS_RIGHTS` row whose English display name is *Admin Access*.

So the way you nominate a fulfiller is: **grant the `ADMIN` access right on the manual managed system's resource** to one user, or to one group. A user grant wins over a group grant, so granting both does not give you two fulfillers — it gives you the user.

### 3. It resolves that to a candidate list

* **A user** → that one user, and their display name becomes the step's approver name.
* **A group** → **every member of the group**, resolved from the search index, with the group's name as the step name. Because it reads the index, a member added seconds earlier may be missed; reindex if a new fulfiller is not getting tasks.
* **No admin, or an empty group** → it falls back to `org.openiam.idm.activiti.default.approver.user`, shipped **`3000`** (`sysadmin`).

### 4. OpenIAM assigns or offers the task

The same one-versus-many rule as every other flow applies: **exactly one candidate → the task is assigned outright** and `AssigneeUserId` is set; **more than one → each is added as a candidate**, so the task appears in several inboxes and must be **claimed** before anyone can complete it. That is why a group of fulfillers always sees **Claim** before **Complete**, and it is not a permissions fault.

Combined with the shipped approver associations that also point at `3000`, a default installation therefore sends both the approval **and** the fulfilment of every manual request to the same unmonitored inbox. Granting the **Admin Access** right on each manual managed system's resource is the single change that makes this feature work.

## Notification, and why it comes from an unusual place

The `manualTask` flow has no notification step of its own, so the fulfiller's mail is sent as part of task assignment instead. Three consequences:

* **It notifies every candidate except the requester.** If the requester happens also to be the resource's admin, they get the task and no mail about it.
* **It goes through the custom notification script**, named by `org.openiam.activiti.custom.notification.groovy.script` and shipped as `bpm/CustomNotificationDelegate.groovy`. So customising manual-task notification means editing that script in Groovy Manager — changing a mail template alone will not do it.
* **It is audited as `TASK_LISTENER`, carrying the `CANDIDATE_USER_IDS` attribute.** That entry is your proof of who was notified, and comparing its value against who you granted the admin right to is the fastest way to find a misconfigured fulfiller.

On completion, both the **target user** and the **requester** are notified, through the same script.

## What the fulfiller sees, and how they complete it

The fulfiller opens **SelfService → Inbox**. The two routes are `/selfservice/myTasks?showTasksAssignedToMe=true` for the list and `/selfservice/task?id=<TASK_ID>` for the task. The SelfService dashboard's approvals tile links to a filtered form of the list whose `workflow` parameter names `manualTask` alongside the approval flows, so **manual tasks and access requests share one inbox** — a fulfiller does not get a separate queue.

The task screen recognises a manual task from its `WorkflowName`, and that changes the buttons:

| Task kind         | Buttons offered                                                    |
| ----------------- | ------------------------------------------------------------------ |
| Ordinary approval | **Approve** and **Reject**                                         |
| Manual task       | **Complete** only — `openiam.ui.selfservice.task.complete.request` |

Both are disabled while the step has more than one candidate and the task is unclaimed, so a group fulfiller sees **Claim** first.

The instruction text is the `UserNotes` variable, rendered read-only in the field labelled *Reason for Request*. When nothing supplied a description, OpenIAM generates it:

> Based on approved request #`<requestId>`, for `<resource>` system please add user `<displayName>` to the following object:

followed by the names of the roles being added, with dates formatted per `org.openiam.date.format`. The revocation and termination paths supply their own text — *"Based on request, please revoke access in `<resource>` system…"* and *"User `<displayName>` login: `<login>` was terminated, please terminate his account in `<resource>` system"*.

**Those strings are not mail templates and are not editable from the Webconsole**, and they are not localizable either. This is a genuine limit rather than a setting you have not found: there is no screen that changes them. If you need different wording, the only route is to supply a description when the task is initiated, from a script — which is a development change, not configuration.

**Completion.** The **Complete** button sends an accepted decision, which sets `STATUS` to `COMPLETED`, satisfies the flow's completion condition and runs the completion step. The on-screen confirmation is the `TASK_COMPLETED` message.

There is a second path, used by integrations rather than by the screen: a caller may supply a status explicitly. That form completes the task **only when the status is exactly `COMPLETED`**; a status of `addcomment` preserves the existing status, and anything else updates the task's variables and leaves it open. It audits `COMPLETE_WORKFLOW` when completing and `UPDATE_WORKFLOW` otherwise, and confirms with `TASK_UPDATED`. Two guards produce specific errors on this path: `TASK_MUST_BE_CLAIMED` when the task is unclaimed and has no assignee, and `ACCESS_DENIED` when the caller is not one of its candidates.

## What completion actually records

On completion OpenIAM does three things:

1. Reads the original request back out of the process, and the target user from the `AssociationId` variable.
2. **Removes** the `PENDING_MANUAL_ASSIGNMENT` tag from every role and group on that user, and saves those memberships.
3. Notifies the target user and the requester.

So the durable record of fulfilment is **the absence of the tag** plus the audit trail. There is no "fulfilled" column and no evidence that the work was really done in the target — a manual task is an attestation, not a verification. If you need proof, ask for a reference number in the comment and read `TASK_HISTORY`.

The membership itself was written earlier than that. On the access-request path OpenIAM saves the user first and creates the manual task afterwards, so from the moment the request completes OpenIAM's own record says the user holds the access, tagged, while the work in the other system has not started. Reconciliation has to expect a window in which OpenIAM and the target disagree, and it has to treat the target as authoritative for whether the change happened.

{% hint style="warning" %}
**A pending manual assignment is invisible to governance.** While the tag is present, the entitlement is:

* **dropped from certification campaign generation** — no review item is created for it;
* **reported as excluded by a campaign preview**, with the reason `ENTITLEMENT_PENDING_MANUAL_ASSIGNMENT`, shown as *Entitlement pending manual assignment*. That is your observable check: run a preview and read the Excluded tab;
* **ignored as a grant path by the risk engine**, so it contributes nothing to a user's risk score.

An abandoned manual task therefore hides an entitlement from review indefinitely. Monitor open `manualTask` process instances as an operational metric, not just as user complaints.
{% endhint %}

## Email-based fulfilment and approval

This exists and is real, but it is narrower than people expect. The **email-manager** service sweeps an IMAP inbox and turns replies into task decisions.

**The mechanism.** On a fixed interval, and on exactly one node however many you run, OpenIAM connects to each mailbox configuration whose inbox is enabled, opens the template's inbox folder, and processes every **unseen** message. Each message is replied to with the outcome, and marked seen — so a message is processed once, and re-marking it unread will get it processed again.

| Setting                                         | Where                                                         | Shipped default                                         |
| ----------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------- |
| `org.openiam.email.inbox.sweep`                 | Set with the `email-manager` service's properties             | `900000` — **15 minutes**                               |
| **Read Inbox?** (`MAILBOX_CONFIG.ACTIVE_INBOX`) | Administration → Mailbox Configurations                       | `N` — the sweep processes nothing until you turn it on  |
| IMAP host, port, SSL, inbox folder              | The mailbox configuration **template**, not the configuration | e.g. `imap.gmail.com` / `993` / `INBOX` for `GMAIL_MBT` |

Full mailbox and template configuration is [Mail and notifications](/administration-guide/platform/mail-and-notifications.md).

**The three recognised actions.** OpenIAM matches each message's body and subject against these patterns, in this order, and rejects the message with `NOT_RECOGNIZED_INCOMING_EMAIL` if none match:

| Action     | Body pattern (multiline, case-insensitive)                                                           | Subject pattern | Needs a target user                 |
| ---------- | ---------------------------------------------------------------------------------------------------- | --------------- | ----------------------------------- |
| `DELEGATE` | `delegate.*\s([_A-Za-z0-9-^+]+(.[_A-Za-z0-9-+]+)*\@[A-Za-z0-9-]+(.[A-Za-z0-9]+)*\.[A-Za-z]{2,})\s*?` | `([0-9]*)$`     | yes — the email address in the body |
| `APPROVE`  | `I accept this request`                                                                              | `([0-9]*)$`     | no                                  |
| `REJECT`   | `I reject this request`                                                                              | `([0-9]*)$`     | no                                  |

So the reply must contain the literal sentence **"I accept this request"** or **"I reject this request"**, and the subject must **end with the request ID digits**. Both outcomes take exactly the same path as the **Approve** and **Reject** buttons, and record the comment `<displayName> send <APPROVE|REJECT> command by email` — which is how you tell an email decision from a console one after the fact.

**Sender and task resolution.** The sender's address is matched to exactly one user by an exact email search against the index — no match raises `NO_USER_FOUND_FOR_GIVEN_EMAIL`, two or more raise `EMAIL_ADDRESS_DUPLICATED`. The task is then found by request ID, first among tasks **assigned** to the sender and, failing that, among tasks they are a **candidate** for, so a fulfiller group member can respond without claiming first. No match raises `NOT_FOUND` with *Task not found for requestId=…*; two raise `DUPLICATE_IDENTIFIER`.

**Every decision is audited** as `MAKE_DECISION_FROM_EMAIL`, source `EMAIL_MANAGER`, with the attributes `Responded email address`, `Request ID` and `Response`. Failures record their reason: `Email with subject <subject> is not for automatic processing` for an unrecognised message, and `Email with given type recognized, but not supported in current release not supported` for an action the release does not implement. Both are worth an audit-log filter if you enable this — an unrecognised reply is otherwise completely silent to the person who sent it.

{% hint style="warning" %}
**Email decisions are approve/reject, not "complete".** An `I accept this request` reply on a manual task takes the accepted path, which sets `STATUS` to `COMPLETED` and does complete the task correctly. An `I reject this request` reply sets `REJECTED`, which on `manualTask` lands on the dead branch described above — the tag is never removed and the entitlement is hidden from governance with nothing on screen to say so. **Do not enable email responses on manual-task notifications unless you are certain your users will never reject one.**

Two further limits worth stating plainly. The sweep authenticates to IMAP with the mailbox configuration's **SMTP** username and password, so the same credential must work for both protocols — there is no separate IMAP credential field, and looking for one is a waste of time. And there is **no signature, token or nonce** on the reply: trust is the sender's email address alone, which anyone can forge. Treat email approval as a convenience for low-risk requests, not as an authenticated control, and say so in your control documentation.
{% endhint %}

## Related

* [Approval flows](/administration-guide/requests/approval-flows.md) — the decision that happens before fulfilment, and the shipped `sysadmin` default
* [The request catalog and questionnaires](/administration-guide/requests/request-catalog.md) — making the manual application requestable
* [Shipped approval workflows](/administration-guide/reference/shipped-workflows.md) — `manualTask` alongside the other 48 definitions
* [Mail and notifications](/administration-guide/platform/mail-and-notifications.md) — mailbox configurations, templates and the inbox sweep
* [Membership tags](/administration-guide/governance/certification/membership-tags.md) — what the `PENDING_MANUAL_ASSIGNMENT` tag means to governance
* [Configure a managed system](/administration-guide/lifecycle/configure-managed-system.md) — every other field on the screen where **Manual** lives
* [Change configuration safely](/administration-guide/start/change-safely.md) — why the first manual request is one disposable user

*Applies to OpenIAM 2026.8.1. Last reviewed 7 August 2026.*


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.openiam.com/administration-guide/requests/fulfilment.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
