How can i can send windows 10 notifications with python that has a button on the notification

Viewed 9593

How can I use python to send notifications that support buttons, and stay in the action/notificaton center?

I am trying to make an app that reminds me to do stuff, and the notification will have a complete, and a snooze button. I tried using the win10toast package, but the notification didnt stay in the action center, and it did not support putting buttons on it.

The notification should look similar to this:

enter image description here

Thanks!

6 Answers

Maybe too late but this code should show a sample notification with buttons:

import winrt.windows.ui.notifications as notifications
import winrt.windows.data.xml.dom as dom

app = '{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}\\WindowsPowerShell\\v1.0\\powershell.exe'

#create notifier
nManager = notifications.ToastNotificationManager
notifier = nManager.create_toast_notifier(app)

#define your notification as string
tString = """
  <toast>
    <visual>
      <binding template='ToastGeneric'>
        <text>Sample toast</text>
        <text>Sample content</text>
      </binding>
    </visual>
    <actions>
      <action
        content="Delete"
        arguments="action=delete"/>
      <action
        content="Dismiss"
        arguments="action=dismiss"/>
    </actions>        
  </toast>
"""

#convert notification to an XmlDocument
xDoc = dom.XmlDocument()
xDoc.load_xml(tString)

#display notification
notifier.show(notifications.ToastNotification(xDoc))

Unfortunately, win10toast cheats and displays old-style, Windows XP notifications, not toasts. A Toast's content is specified using XML and can contain buttons, formatting, images etc.

To display a toast, one has to use WinRT. Luckily, someone wrote a real answer recently, using the Python/WinRT package.

I won't vote to close as duplicate, because the upvoted answers to that question all work with notifications, not toasts. Please go upvote that answer.

The linked answer explains how to install Python/WinRT with :

pip install winrt

Then uses it with surprisingly little code:


import winrt.windows.ui.notifications as notifications
import winrt.windows.data.xml.dom as dom

#create notifier
nManager = notifications.ToastNotificationManager
notifier = nManager.create_toast_notifier();

#define your notification as string
tString = """
<toast>
    <visual>
        <binding template='ToastGeneric'>
            <text>Sample toast</text>
            <text>Sample content</text>
        </binding>
    </visual>
</toast>
"""

#convert notification to an XmlDocument
xDoc = dom.XmlDocument()
xDoc.load_xml(tString)

#display notification
notifier.show(notifications.ToastNotification(xDoc))

The Toast Content article explains how the content is created, either through code or XML. Buttons are described here, eg :

    <actions>

        <action
            content="See more details"
            arguments="action=viewdetails&amp;contentId=351"
            activationType="foreground"/>

        <action
            content="Remind me later"
            arguments="action=remindlater&amp;contentId=351"
            activationType="background"/>

    </actions>

Once an action is selected, the arguments are sent to the application

I will use win10toast module. First use:

pip install win10toast

In cmd to install it.

Then to import it:

from win10toast import ToastNotifier

A sample notification:

toast = ToastNotifier()
toast.show_toast("Notification title","Notification body",duration=DURATION,icon_path="ICON PATH")

I don't have enough rep to just comment a link to my other answer...but I've found a solution using WinRT that displays buttons that are usable from within your Python code (unlike the answer that only provides a "dismiss" option). I started from the other WinRT answer here but that one has errors and is missing critical steps.

I've written out more details over here, but I'll provide just the code from that for those that just want a solution. As a useful example, the following code (Python 3.9) will open your "Documents" folder in a Windows Explorer window using subprocess call in the handle_activated function.

import os,sys,time
import subprocess
import threading
import winrt.windows.ui.notifications as notifications
import winrt.windows.data.xml.dom as dom

# this is not called on the main thread!
def handle_activated(sender, _):
    path = os.path.expanduser("~\Documents")
    subprocess.Popen('explorer "{}"'.format(path))

def test_notification():
    #define your notification as
    tString = """
    <toast duration="short">

        <visual>
            <binding template='ToastGeneric'>
                <text>New notifications</text>
                <text>Text</text>
                <text>Second text</text>
            </binding>
        </visual>

        <actions>
            <action
                content="Test Button!"
                arguments=""
                activationType="foreground"/>
        </actions>

    </toast>
    """

    #convert notification to an XmlDocument
    xDoc = dom.XmlDocument()
    xDoc.load_xml(tString)
    notification = notifications.ToastNotification(xDoc)

    # add the activation token.
    notification.add_activated(handle_activated)

    #create notifier
    nManager = notifications.ToastNotificationManager
    #link it to your Python executable (or whatever you want I guess?)
    notifier = nManager.create_toast_notifier(sys.executable)

    #display notification
    notifier.show(notification)
    duration = 7 # "short" duration for Toast notifications

    # We have to wait for the results from the notification
    # If we don't, the program will just continue and maybe even end before a button is clicked
    thread = threading.Thread(target=lambda: time.sleep(duration))
    thread.start()
    print("We can still do things while the notification is displayed")

if __name__=="__main__":
    test_notification()

You could use the toast64.exe application from https://github.com/go-toast/toast. It supports Buttons, App name, Notification duration and Notification Sound. It is quite easy to use. This is far more better than other python modules like plyer, win10toast, py-notifier, pynotify etc.

This is a code snippet from the above Github page:-

C:\Users\Example\Downloads\toast64.exe \
  --app-id "Example App" \
  --title "Hello World" \
  --message "Lorem ipsum dolor sit amet, consectetur adipiscing elit." \
  --icon "C:\Users\Example\Pictures\icon.png" \
  --audio "default" --loop \
  --duration "long" \
  --activation-arg "https://google.com" \
  --action "Open maps" --action-arg "bingmaps:?q=sushi" \
  --action "Open browser" --action-arg "http://..."

You can use buttons in winrt like this:

import winrt.windows.ui.notifications as notifications
import winrt.windows.data.xml.dom as dom
import sys

# get python path
path = sys.executable

#create notifier
nManager = notifications.ToastNotificationManager
notifier = nManager.create_toast_notifier(path)

#define your notification as

tString = """
<toast>

    <visual>
        <binding template='ToastGeneric'>
            <text>New notifications</text>
            <text>Text</text>
            <text>Second text</text>
        </binding>
    </visual>

    <actions>
        <input id="textBox" type="text" placeHolderContent="Type a reply"/>
        <action
            content="Send"
            arguments="action=reply&amp;convId=01"
            activationType="background"
            hint-inputId="textBox"/>
            
        <action
            content="Button 1"
            arguments="action=viewdetails&amp;contentId=02"
            activationType="foreground"/>
    </actions>

</toast>
"""

#convert notification to an XmlDocument
xDoc = dom.XmlDocument()
xDoc.load_xml(tString)

# this is not called on the main thread.
def handle_activated(sender, _):
    print([sender, _])
    print('Button was pressed!')

# add the activation token.
activated_token = notification.add_activated(handle_activated)

#display notification
notifier.show(notifications.ToastNotification(xDoc))

Where I learnt about this: this issue.

Related