Send a Raw Request to a Postfix Service with postkick
You reach for postkick when some other tool tells you to "kick" a Postfix service and gives you a request string but no explanation of how to send it. It talks to a Postfix service over its local IPC socket, using the postkick from Postfix 3.8.6, installed here as package version 3.8.6-1ubuntu0.1. Budget fifteen minutes if you already know the class, service and request you need.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need a shell, the postfix package, and a local Postfix configuration. This is an administrative interface, not a mail submission tool: it takes no message body, and there is no universal list of requests, because the valid string belongs to whichever service you are calling.
1. Confirm the installed command and configuration
Start with read-only checks. None of these need elevated privileges:
$ command -v postkick
/usr/sbin/postkick
$ dpkg-query -W -f='${Package} ${Version}\n' postfix
postfix 3.8.6-1ubuntu0.1
$ postconf -h config_directory
/etc/postfix
The installed manual gives the syntax as postkick [ -c config_dir ] [ -v ] class service request. Run it bare and it refuses, because all three positional arguments are compulsory:
$ postkick
postkick: fatal: usage: postkick [-c config_dir] [-v] class service request
Checkpoint
If command -v finds a different binary, or the package version differs, read that machine's own manual before trusting anything below.
2. Work out the class and the service name
The first argument is the transport class: public for an endpoint any local user can reach, private for an administrative one. The second is the service name inside that class. The manual maps these to /var/spool/postfix/public and /var/spool/postfix/private.
- Never guess the class or service. Read the local
master.cfand the documentation for whatever owns the endpoint. - Never reuse a request string from another service. A request valid for one service can be meaningless, or do something unexpected, on another.
$ config_dir=$(postconf -h config_directory)
$ grep -E '^[[:alnum:]_-]+[[:space:]]+(unix|fifo|pass|unix-dgram)' "$config_dir/master.cf"
# review the local service definitions before choosing SERVICE_NAME
That output is host-specific. Keep the variable local to this session, and only fill in SERVICE_NAME once the owning service's own docs have told you what it expects.
3. Send the request
Once class, service and request are all confirmed from the service's own documentation, the shape is:
$ postkick CLASS SERVICE_NAME REQUEST_STRING
Which, filled in as a template rather than something to paste unchanged, looks like:
$ postkick public SERVICE_NAME REQUEST_STRING
Quote the request as one argument if it contains whitespace:
$ postkick public SERVICE_NAME 'REQUEST STRING WITH SPACES'
A successful call is normally silent. If a script needs to branch on the result, capture the status right away:
$ postkick public SERVICE_NAME REQUEST_STRING
$ status=$?
$ printf 'postkick exit status: %s\n' "$status"
postkick exit status: 0
Tip
A zero status only says the IPC transaction completed. It does not prove the service finished every later operation you were hoping for. Check the service's own logs or status interface as a separate step.
4. Treat private endpoints as an administrative boundary
A private endpoint is not just public with a different name. The manual calls it administrative access only, so use the least privileged account authorised for the service. If elevation is genuinely required, wrap the whole command in sudo and read the request one more time before running it:
$ sudo /usr/sbin/postkick private SERVICE_NAME REQUEST_STRING
Warning
Depending on the service and request, this can wake, reload or otherwise change a running daemon. Stop here if you cannot explain what the request will do. There is no generic undo in postkick itself; recovery is the service's job, via its documented inverse request, a restored configuration, or its own recovery procedure.
5. Point at another configuration directory
Use -c when the target Postfix instance keeps main.cf somewhere other than the default:
$ postkick -c /path/to/postfix-config CLASS SERVICE_NAME REQUEST_STRING
Check that directory actually holds what that instance expects before sending anything:
$ test -r /path/to/postfix-config/main.cf && echo 'main.cf is readable'
main.cf is readable
MAIL_CONFIG also names a configuration directory, and MAIL_VERBOSE turns on verbose logging. Prefer an explicit -c in scripts, because the target is then visible right at the point of use. Double-check endpoint paths and instance ownership so a test configuration never ends up talking to a production socket by accident.
6. Diagnose a failed transaction
Errors go to standard error. Rerun the read-only checks first, then look at the exact command shape:
$ postkick -v CLASS SERVICE_NAME REQUEST_STRING
$ printf 'exit status: %s\n' "$?"
exit status: 0
Add -v for debugging; repeat it for more verbosity if the installed build supports it. A non-zero status usually means one of these, in roughly descending order of likelihood:
- Missing socket. The class or service socket does not exist.
- Wrong configuration. The selected config points at the wrong queue directory.
- Permission denied. The account lacks access to a private endpoint.
- Bad request. The string is not valid for that particular service.
Read the diagnostic text rather than treating every failure as a Postfix-wide outage. Check the relevant paths without touching them:
$ postconf -h queue_directory
/var/spool/postfix
$ ls -ld /var/spool/postfix/private /var/spool/postfix/public
Do not create socket paths, change their ownership, or restart Postfix just because a guessed request failed. Those are separate operational changes, and they can disrupt mail handling on their own.
Done means
- Version checked. The command and Postfix package version match what this guide assumes.
- Class and service confirmed. Both came from local configuration or the service's own documentation, never a guess.
- Least privilege used. Public endpoints preferred; private access treated as an administrative act.
- Status captured. Exit status and stderr checked immediately after each call.
- Recovery known. Any service-side effect has a documented way back before you sent the request.