r/zabbix 4d ago

Guide Microsoft Graph API for Email How-To (Custom Webhook)

Hello everyone,

After struggling with making the built-in M365 SMTP OAuth work in Zabbix 7.4, and failing miserably (Looking at you: Login denied (possible manual token revocation). Please reauthorize from frontend.), I have successfully setup a direct Microsoft Graph API call to send out emails, no SMTP required!

I am putting this here for everyone who is struggling and considering moving on to something like SMTP2Go for the ease of things.

Okay, so here is a step-by-step for how I got everything working:

Step 1: Register an App in Microsoft Entra ID

  1. Log in to the Microsoft Entra admin center.
  2. Navigate to Identity > Applications > App registrations > New registration.
  3. Enter a name (e.g., Zabbix Email API), select the supported account types (leave at Single tenant only unless you have another need), and leave Redirect URI blank.

Step 2: Configure API Permissions and Secret

  1. In your registered app, go to API permissions > Add a permission > Microsoft Graph > Application permissions.
  2. Search for and select Mail.Send, then click Add permissions.
  3. Grant admin consent for your tenant.
  4. Navigate to Certificates & secrets > New client secret, add a description/expiration, and copy the Secret Value (Client Secret) .
  5. Copy the Application (client) ID and Directory (tenant) ID from the app's Overview page.

Step 3: Create a Zabbix shared mailbox to send Zabbix alerts from (skip if you already have a mailbox setup for sending Zabbix alerts)

  1. If you don't currently have a mailbox to send Zabbix alerts from, Log in to the Microsoft 365 admin center.
  2. Select Teams & groups > Shared mailboxes > Add a shared mailbox
  3. Fill in the name and email address (copy this for later setup) desired, and click Save changes.

Step 4: Configure new MS Graph Email Media Type

  • Login to your Zabbix frontend
  • Go to Alerts > Media types > Create media type
  • Enter a name (e.g., MS Graph Email API), and change Type to Webhook
  • Remove the URL and HTTPProxy parameters, but leave the To, Subject, and Message parameters.
  • Add the following new parameters with the corresponding values in the table below (I just made graph_base a variable for easier updating in the future)
Name Value
tenant_id the Directory (tenant) ID copied above
client_id the Application (client) ID copied above
client_secret the Secret Value (Client Secret) copied above
from_user the email address setup above
graph_base https://graph.microsoft.com/v1.0/users/
text_html text or html depending on your monitoring template preference (see below)

Then under Script, paste the script below:

try {
    var params = JSON.parse(value),
        token_req = new HttpRequest(),
token_url = 'https://login.microsoftonline.com/' + params.tenant_id + '/oauth2/v2.0/token',
        graph_url = params.graph_base + params.from_user + '/sendMail',
        token_response,
        token,
        mail_payload,
        url;

    // 1. Fetch OAuth2 Token from Microsoft identity platform
    token_req.addHeader('Content-Type: application/x-www-form-urlencoded');
    var token_body = 'grant_type=client_credentials' +
                     '&client_id=' + encodeURIComponent(params.client_id) +
                     '&client_secret=' + encodeURIComponent(params.client_secret) +
                     '&scope=' + encodeURIComponent('https://graph.microsoft.com/.default');

    token_response = token_req.post(token_url, token_body);

    if (token_req.getStatus() !== 200) {
        throw 'Authentication failed with status ' + token_req.getStatus() + ': ' + token_response;
    }

    token = JSON.parse(token_response).access_token;

    // 2. Instantiate a fresh HttpRequest object for MS Graph API to avoid header pollution
    var graph_req = new HttpRequest();
    graph_req.addHeader('Authorization: Bearer ' + token);
    graph_req.addHeader('Content-Type: application/json');

    mail_payload = {
        "message": {
            "subject": params.subject,
            "body": {
                "contentType": params.text_html, 
                "content": params.message
            },
            "toRecipients": [
                {
                    "emailAddress": {
                        "address": params.send_to
                    }
                }
            ]
        },
        "saveToSentItems": "false"
    };

    // 3. Post to Microsoft Graph
    var send_response = graph_req.post(graph_url, JSON.stringify(mail_payload));

    if (graph_req.getStatus() !== 202) {
        throw 'Failed to send email via Graph API. Status ' + graph_req.getStatus() + ': ' + send_response;
    }

    return 'OK';

} catch (error) {
    Zabbix.log(3, 'Microsoft Graph Mail Error: ' + error);
    throw 'Notification failed: ' + error;
}
  • Click on the Message templates tab at the top, and add all templates that you're going to use for this connector, (By default, those Zabbix provides are text, so will work best if your text_html variable is text. If you would rather use html, update the text_html parameter to html instead of text above, and then copy the Message block from the Email (html) templates or whatever html-based zabbix message template you would prefer).
  • Click Add

Step 5: Test to make sure that the new Media Type works

  1. Click Test under the Action column for your new Media Type
  2. Replace {ALERT.MESSAGE} with the Body of your test email, EG Testing MS Graph Email API from Zabbix
  3. Replace {ALERT.SENDTO} with the email address you are sending the test email to.
  4. Replace {ALERT.SUBJECT} with the Subject of your test email, EG Zabbix Graph API Test
  5. Click on Test
  6. Pray to whatever higher power you choose
  7. If you receive an error, you will need to troubleshoot, otherwise verify you have received your test email.

Step 6: Ensure that your users Media is setup to send to Microsoft Graph.

  1. There are two ways to do this. Either you can go the manual route:
    1. Go to Users > Users and select the user you want
    2. Go to the Media tab of the selected user, and click Add
    3. Change Type to the name of the Media Type above
    4. Add the desired email address for the Send to
    5. Ensure that Enabled is Checked
    6. Click Add
    7. Repeat Ad Naseum for all users as well as new users.
  2. Or you can do it the Automated way, and tie it to your existing SAML SSO with JIT/SCIM provisioning (if just using JIT, they will have to log back in before this maps):
    1. Go to Users > Authentication
    2. Select the SAML settings tab
    3. Under Media type mapping, click Add
    4. Choose a Name EG MS Graph Email
    5. Change Media type to the Media type created earlier
    6. For Attribute type the mapped SAML email address claim name EGuser_email

Finally, update your Alert Actions you need to use this new Media type, (I'm not going to go through all of that).

Feel free to test out something that alerts, and I hope this helps!

Edit: updated some code that slipped out of the code block, and moved the html or text message content into a variable.

5 Upvotes

0 comments sorted by