In the previous post on deploying Sieve filters to Stalwart using JMAP the workflow always created a new script. After some testing I realised it should update the existing script when one already exists. Below is the corrected workflow.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
| name: Deploy to Stalwart
"on":
push:
paths:
- 'stalwart.sieve'
branches:
- main
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install tools
run: |
sudo apt-get update
sudo apt-get install -y jq
- name: Upload via JMAP
env:
STALWART_JMAP_URL: ${{ vars.STALWART_JMAP_URL }}
STALWART_USER: ${{ secrets.STALWART_USER }}
STALWART_PASS: ${{ secrets.STALWART_PASS }}
run: |
set -e
set -x
base_url="${STALWART_JMAP_URL%/jmap*}"
session_json=$(curl -X GET -k -u "$STALWART_USER:$STALWART_PASS" "$base_url/.well-known/jmap")
account_id=$(echo "$session_json" | jq -r '.primaryAccounts["urn:ietf:params:jmap:sieve"]')
jmap_endpoint="${STALWART_JMAP_URL%/}"
upload_url="${jmap_endpoint}/upload/${account_id}"
curl -X POST -k -u "$STALWART_USER:$STALWART_PASS" \
-H "Content-Type: application/sieve" \
--data-binary @stalwart.sieve "$upload_url" > upload.json
blob_id=$(jq -r '.blobId' upload.json)
if [ "$blob_id" = "null" ] || [ -z "$blob_id" ]; then
echo "Upload failed" >&2
cat upload.json
exit 1
fi
list_body=$(jq -n --arg accountId "$account_id" '{
"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:sieve"],
"methodCalls": [["SieveScript/get", {"accountId": $accountId}, "0"]]
}')
list_resp=$(curl -X POST -k -u "$STALWART_USER:$STALWART_PASS" \
-H "Content-Type: application/json" \
-d "$list_body" "$jmap_endpoint")
echo "$list_resp" | jq
existing_id=$(echo "$list_resp" | jq -r '.methodResponses[0][1].list[] | select(.name=="stalwart.sieve") | .id')
if [ -n "$existing_id" ] && [ "$existing_id" != "null" ]; then
set_body=$(jq -n --arg accountId "$account_id" --arg blob "$blob_id" --arg id "$existing_id" '{
"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:sieve"],
"methodCalls": [["SieveScript/set", {
"accountId": $accountId,
"update": {($id): {"blobId": $blob}},
"onSuccessActivateScript": $id
}, "0"]]
}')
else
set_body=$(jq -n --arg accountId "$account_id" --arg blob "$blob_id" '{
"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:sieve"],
"methodCalls": [["SieveScript/set", {
"accountId": $accountId,
"create": {"A": {"name": "stalwart.sieve", "blobId": $blob}},
"onSuccessActivateScript": "#A"
}, "0"]]
}')
fi
curl -X POST -k -u "$STALWART_USER:$STALWART_PASS" \
-H "Content-Type: application/json" \
-d "$set_body" "$jmap_endpoint" | jq
|
This version first queries existing scripts and either updates the current one or creates it if missing.
This post was written with the assistance of an AI tool.
Author
Arran Ubels
LastMod
2025-06-09
License
MIT No Attribution