All commands assume you are logged in as a non-root user with sudo access.
1. Install dnf5-automatic
sudo dnf install -y dnf5-plugin-automaticUsing Amazon SES? You will also need the boto3 Python library:
sudo dnf install -y python3-boto32. Copy the default configuration file
sudo cp /usr/share/dnf5/dnf5-plugins/automatic.conf /etc/dnf/automatic.conf3. Configure automatic.conf
Run the following commands to apply the required settings. Choose the block that matches your mail provider — the only difference is the command_format line.
Common settings (apply for both providers)
# Enable automatic updates
sudo sed -i 's/^apply_updates = no$/apply_updates = yes/' /etc/dnf/automatic.conf
# Reboot when needed after updates
sudo sed -i 's/^reboot = never$/reboot = when-needed/' /etc/dnf/automatic.conf
# Shorten the reboot delay from 5 minutes to 1 minute
sudo sed -i "s/^reboot_command = \"shutdown -r +5/reboot_command = \"shutdown -r +1/" /etc/dnf/automatic.conf
# Route output through a custom command instead of stdio
sudo sed -i 's/^emit_via = stdio$/emit_via = command/' /etc/dnf/automatic.conf
# Uncomment and set stdin_format so the report body is piped to the command
sudo sed -i 's/^# stdin_format = "{body}"/stdin_format = "{body}"/' /etc/dnf/automatic.confSet the command for your mail provider
Microsoft Graph API:
sudo sed -i 's|^# command_format = "cat"|command_format = /usr/local/sbin/dnf-auto-mail-api graph|' /etc/dnf/automatic.confAmazon SES:
sudo sed -i 's|^# command_format = "cat"|command_format = /usr/local/sbin/dnf-auto-mail-api ses|' /etc/dnf/automatic.conf4. Obtain API credentials
Before proceeding, gather the credentials for your chosen provider.
Microsoft Graph API
You will need an Entra ID (Azure AD) App Registration with the Mail.Send application permission granted (admin-consented). Collect:
| Value | Description |
|---|---|
tenant_id | Your Microsoft 365 tenant ID |
client_id | The App Registration's Application (client) ID |
client_secret | A client secret generated for the App Registration |
sender | The mailbox the Graph API will send from (e.g. noreply@domain.com) |
email_from | The address shown in the From header (usually the same as sender) |
email_to | Space-separated list of recipient addresses |
Amazon SES
You will need IAM credentials with ses:SendEmail permission. Collect:
| Value | Description |
|---|---|
region | AWS region for SES (e.g. us-east-1) |
aws_access_key_id | IAM access key ID |
aws_secret_access_key | IAM secret access key |
aws_session_token | (Optional) Session token if using temporary credentials |
configuration_set | (Optional) SES configuration set name |
email_from | Verified sender address in SES |
email_to | Space-separated list of recipient addresses |
5. Create the credentials file
The credentials are stored in /root/.dnf-mail-api. Create the file with the appropriate section for your provider.
Microsoft Graph API
sudo tee /root/.dnf-mail-api > /dev/null <<'EOF'
[graph]
tenant_id = xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
client_id = xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
client_secret = YOUR_SECRET_HERE
sender = noreply@domain.com
email_from = noreply@domain.com
email_to = someadmin@domain.com
subject_prefix = [HostName]
expire = 2028-03-31
EOFAmazon SES
sudo tee /root/.dnf-mail-api > /dev/null <<'EOF'
[ses]
region = us-east-1
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = YOUR_SECRET_KEY_HERE
email_from = noreply@domain.com
email_to = someadmin@domain.com
subject_prefix = [HostName]
expire = 2028-03-31
EOFReplace all placeholder values with your real credentials. The subject_prefix is prepended to every email subject — set it to something that identifies the host (e.g. [WebServer], [Relay]). The expire field is informational — use it to track when the client secret or IAM key needs to be rotated.
Lock down file permissions
sudo chmod 600 /root/.dnf-mail-apiThe dnf-auto-mail-api script enforces 0600 permissions and will refuse to run if the file is world- or group-readable.
6. Install the mail script
Download and deploy the dnf-auto-mail-api Python script to /usr/local/sbin/:
sudo wget -O /usr/local/sbin/dnf-auto-mail-api https://meikakuconsulting.com/guides/dnf/dnf-auto-mail-api
sudo chmod 0750 /usr/local/sbin/dnf-auto-mail-api
sudo chown root:root /usr/local/sbin/dnf-auto-mail-apiVerify the script compiles
sudo python3 -m py_compile /usr/local/sbin/dnf-auto-mail-apiIf this command produces no output, the script is syntactically valid.
7. Enable and start the timer
sudo systemctl enable --now dnf5-automatic.timerThis schedules dnf5-automatic to run on its default cadence (typically daily).
8. Test manually
To verify everything works end-to-end without waiting for the timer:
sudo dnf5 automaticAn email is only sent when there are updates to report. If the system is already fully current, the command will run and produce no output — this is normal.
To validate the email pipeline on a system that is already up to date, temporarily enable reporting when no updates are available:
# Enable "no updates" notifications for testing
sudo sed -i 's/^emit_no_updates = no$/emit_no_updates = yes/' /etc/dnf/automatic.conf
# Run the test
sudo dnf5 automatic
# Disable "no updates" notifications (restore default)
sudo sed -i 's/^emit_no_updates = yes$/emit_no_updates = no/' /etc/dnf/automatic.confTroubleshooting
| Symptom | Likely Cause |
|---|---|
Config file not found: /root/.dnf-mail-api | The credentials file was not created or is in the wrong location. |
permissions are 0o644, expected 0o600 | Run sudo chmod 600 /root/.dnf-mail-api to fix permissions. |
[graph] missing required key: ... | A required field is blank or missing in the credentials file. |
Failed to obtain Graph token | Check tenant_id, client_id, and client_secret values. Verify the App Registration has Mail.Send permission with admin consent. |
boto3 is not installed | Run sudo dnf install -y python3-boto3. |
SES send_email failed | Verify IAM credentials, region, and that the sender address is verified in SES. |
| Script runs but no email arrives | Confirm email_to contains the correct recipient address(es). Check spam folders. |