Platypush

Leverage the RSS and HTML scraping capabilities of Platypush to set up automations to deliver articles to an e-reader.

Author photo Platypush
.

RSS feeds are a largely underestimated feature of the web nowadays — at least outside the circles of geeks. Many apps and paid services exist today to aggregate and curate news from multiple sources, often delegating the task of selecting articles and order on the screen to an opaque algorithm, and the world seem to have largely forgotten this two-decade old technology that already solved the problem of news curation and aggregation a while ago.

However, RSS (or Atom) feeds are much more omnipresent than many think - every single respectable news website provides at least one feed, albeit some news outlets may not advertise them much amid the fears of losing organic traffic. Feeds empower users with the possibility of creating their own news feeds and boards through aggregators, without relying on the mercy of a cloud-run algorithm. And their structured nature (under the hood an RSS feed is just a structured XML) offers the possibility to build automation pipelines that deliver the content we want wherever we want, whenever we want, and in whichever format we want.

IFTTT is a popular option to build custom logic on RSS feeds. It makes it very intuitive to build relatively complex rules such as “send me a weekly digest with The Economist articles published in the latest issue” or “send a telegram message with the digest from the NYT every day at 6 a.m.” or “send a notification to my mobile whenever XKCD publishes new comics.” However, IFTTT has recently pivoted to become a paid service with very limited possibility for free users to create new applets.

In my opinion, however, it’s thanks to internet-connected e-readers, such as the Kindle or MobiScribe, as well as web services like Mercury and Instapaper that can convert a web page into a clean print-friendly format, that RSS feeds can finally shine at their full brightness.

It’s great to have our news sources neatly organized in an aggregator. It’s also nice to have the possibility to configure push notifications upon the publication of new articles or daily/weekly/monthly digests delivered whenever we like.

But these features solve only the first part of the problem — the content distribution. The second part of the problem — content consumption — comes when we click on a link, delivered on whichever device and in whichever format we like, and we start reading the actual article.

Such an experience nowadays happens mostly on laptop screens or, worse, tiny smartphone screens, where we’re expected to hectically scroll through often nonmobile-optimized content filled with ads and paywalls, while a myriad of other notifications demand for their share of our attention. Reading lengthy content on a smartphone screen is arguably as bad of an experience as browsing the web on a Kindle is.

Wouldn’t it be great if we could get our favorite content automatically delivered to our favorite reading device, properly formatted and in a comfortably readable size and without all the clutter and distractions? And without having a backlit screen always in front of our eyes?

In this piece, we’ll see how to do this by using several technological tools (an e-reader, a Kindle account, the Mercury API, and Instapaper) and how to glue all the pieces together through Platypush.

Configure your Kindle account for e-mail delivery

I’ll assume in this first section you have a Kindle, a linked Amazon account, and a Gmail account that we’ll use to programmatically send documents to the device via email - although it's also possible to leverage the mail.smtp plugin and use another domain for delivering PDFs. We’ll later see als ohow to leverage Instapaper with other devices.

First, you’ll have to create an email address associated to your Kindle that’ll be used to remotely deliver documents:

  • Head to the Amazon content and device portal, and log in with your Amazon account.

  • Click on the second tab (“Your Devices”), and click on the context menu next to the device where your content should be delivered.

  • You’ll see the email address associated to your device. Copy it, or click on “Edit” to change it.

  • Click on the third tab (“Settings”), and scroll to the bottom to the section titled “Personal Document Settings.”

  • Scroll to the bottom to the section named “Approved Personal Document E-mail List” and add your Gmail address as a trusted source.

To check that everything works, you can now try and send a PDF document to your Kindle from your personal email address. If the device is connected to WiFi, then the document should automatically download within a few seconds.

Configure Platypush

Platypush offers all the ingredients we need for the purpose of this piece. We need, in particular, to build an automation pipeline that:

  • Periodically checks a list of RSS sources for new content
  • Preprocesses the new items by simplifying the web page (through the Mercury parser or Instapaper) and optionally exports them to PDF
  • Programmatically sends emails to your device(s) with the new content

First, install Platypush with the required extras (any device with any compatible OS will do: a RaspberryPi, an unused laptop, or a remote server):

pip install 'platypush[http,pdf,rss,google]'

You’ll also need to install npm and mercury-parser. Postlight used to provide a web API for its parser before, but they’ve discontinued it, choosing to make the project open-source:

apt-get install nodejs npm
npm install @postlight/mercury-parser

Second, link Platypush to your Gmail account to send documents via email:

  • Create a new project on the Google Developers Console.
  • Click on “Credentials” from the context menu > OAuth Client ID.
  • Once generated, you can see your new credentials in the “OAuth 2.0 client IDs” section. Click on the “Download” icon to save them to a JSON file.
  • Copy the file to your Platypush device/server under e.g., ~/.credentials/client_secret.json.
  • Run the following command on the device to authorize the application:
python -m platypush.plugins.google.credentials \
    "https://www.googleapis.com/auth/gmail.modify" \
    ~/.credentials/client_secret.json \
    --noauth_local_webserver
  • Copy the link in your browser; log in with your Google account, if required; and authorize the application.

Now that you’ve got everything in place, it’s time to configure Platypush to process your favorite feeds.

Create a rule to automatically send articles to your Kindle

The http.poll backend is a flexible component that can be configured to poll and process updates from many web resources — JSON, RSS, Atom etc.

Suppose you want to check for updates on The Daily RSS feed twice a day and deliver a digest with the new content to your Kindle.

You’ll want to create a configuration like this in ~/.config/platypush/config.yaml:

backend.http.poll:
    requests:
        # This poll will handle an RSS feed
        - type: platypush.backend.http.request.rss.RssUpdates
          # RSS feed URL and title
          url: http://feeds.podtrac.com/zKq6WZZLTlbM
          title: NYT - The Daily
          # How often we want to check for updates
          # 12h = 43200 secs
          poll_seconds: 43200
          # We want to convert content to PDF
          digest_format: pdf
          # We want to parse and extract the content from
          # the web page using Mercury Parser
          extract_content: True

Create an event hook under ~/.config/platypush/scripts/ that reacts to a NewFeedEvent and sends the processed content to your Kindle via email:

from platypush.event.hook import hook
from platypush.utils import run

from platypush.message.event.http.rss import NewFeedEvent

@hook(NewFeedEvent)
def on_new_feed_digest(event, **context):
    run('google.mail.compose',
        sender='you@gmail.com',
        to='your-kindle@kindle.com',
        subject=f'{event.title} feed digest',
        body=f'Your {event.title} feed digest delivered to your e-reader',
        files=[event.digest_filename])

Restart Platypush. As soon as the application finds items in the target feed that haven’t yet been processed, it’ll parse them, convert them to PDF, trigger a NewFeedEvent that’ll be captured by your hook, and the resulting PDF will be delivered to your Kindle.

You can add more monitored RSS sources by simply adding more items in the requests attribute of the http.poll backend. Now enjoy reading your articles from a proper screen, delivered directly to your e-reader once or twice a day — tiny smartphone screens, paywalls, pop-ups, and ads feel so much more old-fashioned once you dive into this new experience.

Sharing content to your e-reader from your mobile on the fly

RSS feeds are awesome, but they aren’t the only way we discover and consume content today.

Many times we scroll through our favorite social-media timeline, bump into an interesting article, start reading it on our tiny screen, and we’d like to keep reading it later when we are on a bigger screen.

Several tools and products have spawned to provide a solution to the “parse it, save it, and read it later” problem — among those Evernote, Pocket, and Instapaper itself.

Most of them, however, are still affected by the same issue: Either they don’t do a good job at actually parsing and extracting the content in a more readable format (except for Instapaper — Pocket only saves a link to the original content, while Evernote’s content-parsing capabilities have quite some room for improvement, to say the least), or they’re still bound to the backlit screen of the smartphone or computer that runs them.

Wouldn’t it be cool to bump into an interesting article while we scroll our Facebook timeline on our Android device and with a single click deliver it to our Kindle in a nice and readable format? Let’s see how to implement such a rule in Platypush.

First, we’ll need something that runs on our mobile device to programmatically communicate with the instance of Platypush installed on our Raspberry/computer/server.

I consider Tasker one of the best applications suited for this purpose: with Tasker (and the other related apps developed by joaoapps), it’s possible to automate anything on your Android device and create sophisticated rules that connect it to anything.

There are many ways for Tasker to communicate with Platypush (direct RPC over HTTP calls, using Join with an external MQTT server to dispatch messages, using an intermediate IFTTT hook, or Pushbullet, etc.), and there are many ways for Platypush to communicate back to Tasker on your mobile device (using AutoRemote with the Platypush plugin to send custom events, using IFTTT with any service connected to your mobile, using the Join API, or, again, Pushbullet).

We’ll use Pushbullet in this piece because it doesn’t require as many configuration steps as other techniques.

  • Install Tasker, AutoShare, and Pushbullet on your Android device.

  • Go to your Pushbullet account page, and click “Create Access Token” to create a new access token that’ll be used by Platypush to listen for the messages sent to your account. Enable the Pushbullet plugin and backend on Platypush by adding these lines to ~/.config/platypush/config.yaml:

backend.pushbullet:
  token: YOUR-TOKEN
  device: platypush-device

pushbullet:
  enabled: True

Also add a procedure to ~/.config/platypush/scripts that, given an URL as input, extracts the content, converts it to PDF, and sends it to your Kindle:

import re

from platypush.procedure import procedure
from platypush.utils import run

@procedure
def send_web_page_to_kindle(url, **context):
    # Some apps don't share only the link, but also some
    # text such as "I've found this interesting article
    # on XXX". The following action strips out extra content
    # from the input and only extracts the URL.
    url = re.sub(r"^.*(https?://[^\s]*).*", r"\1", url)

    # Extract the content through the Mercury SDK and generate a PDF
    outfile = '/tmp/extract.pdf'
    response = run('http.webpage.simplfy', url=url, outfile=outfile)
    title = response.get('title')

    # Rename the file to match the title of the page
    if title:
      new_outfile = f'/tmp/{response["title"]}.pdf'
      run('file.rename', file=outfile, name=new_outfile)
      outfile = new_outfile

    # Send the file to your Kindle email address
    run('google.mail.compose',
        sender='you@gmail.com',
        to='your-kindle@kindle.com',
        subject=f'{title or "[No Title]"} feed digest',
        body=f'Original URL: {url}',
        files=[outfile])

    # Remove the temporary file
    run('file.unlink', file=outfile)

And don't forget to also include the newly created procedure in ~/.config/platypush/scripts/__init__.py to make sure that it's visible to the application:

from scripts.your_script import send_web_page_to_kindle
  • Restart Platypush, and check from Pushbullet that your new virtual device, platypush-device in the example above, has been created.

  • On your mobile, open AutoShare, select “Manage Commands,” and create a new command named, for example, Send to Kindle.

  • In the task associated with this trigger, tap the plus icon to add a new action, and select “Push a notification” (the action with the green Pushbullet icon next to it)

  • Select “platypush-device” as a target device, and paste the following JSON as message:

{"type":"request", "action":"procedure.send_web_page_to_kindle", "args": {"url":"%astext"}}
  • In the example above, %astext is a special variable in Tasker that contains the text shared by the source app (in this case, the link sent to AutoShare).

  • Open your browser, and go to the web link of an article you’d like to send to your Kindle. Select Share > AutoShare command > Send to Kindle.

  • The parsed article should be delivered to your e-reader in an optimized PDF format within seconds.

Using Instapaper on other Android-based e-readers

I’ve briefly mentioned Instapaper already. I really love both the service as well as the app. I consider it somehow an implementation of what Evernote should have been but has never been.

Just browse to an article on the web, click “Share to Instapaper,” and within one click, that web page will be parsed into a readable format, with all the clutter and ads removed, and it’ll be added to your account.

What makes Instapaper really interesting, though, is the fact that its Android app is really minimal (yet extremely well designed), and it runs well also on devices that run older versions of Android or aren’t that powerful.

That wouldn’t be such a big deal in itself if products like the MobiScribe weren’t slowly hitting the market — and I hope its example will be followed by others. The MobiScribe can be used both as an e-reader and as an e-ink notepad, but what really makes it interesting is that it runs Android — even if it’s an ancient Android Kit-Kat modified release , a more recent version should arrive sooner or later.

The presence of an Android OS is what makes this e-reader/tablet much more interesting than other similar products - like reMarkable, that has better specs, looks better, costs more, but has opted instead to use its own OS, limiting the possibilities to run any apps other than those developed by the company itself. Even if it’s an old version of Android that runs on an underpowered device, it’s still possible to install some apps on it — and Instapaper is one of them.

It makes it very easy to enhance your reading experience: Simply browse the web, add articles to your Instapaper account, and deliver them on the fly to your e-reader. If you want, you can also use the Instapaper API in Platypush to programmatically send content to your Instapaper account instead of your Kindle. Just create a procedure like this:

from platypush.procedure import procedure
from platypush.utils import run

@procedure
def instapaper_add(url, **context):
    run('http.request.get', url='https://www.instapaper.com/api/add',
        params={
          'url': url,
          'username': 'your_instapaper_username',
          'password': 'your_instapaper_password',
        })

I know what you're thinking - the idea of sending my credentials for a web service over a GET request give me shiver as well - but Instapaper has only recently developed an OAuth-based API and I haven't yet managed to implement it in Platypush.

This procedure is now callable through a simple JSON request:

{"type":"request", "action":"procedure.instapaper_add", "args": {"url":"https://custom-url/article"}}

If you prefer this method over the Kindle-over-email way, you can just call this procedure in the examples above to parse the content of the page and save it to your Instapaper account instead of sending an email to your Kindle address.

Conclusions

The amount of information and news channels available on the web has increased exponentially in the last years, but the methods to distribute and consume such content, at least when it comes to flexibility, haven’t improved much. The exponential growth of social media and platforms like Google News means a few large companies nowadays decide which content should appear in front of your eyes, how that content should be delivered to you, and where you can consume it.

Technology should be about creating more opportunities and flexibility, not reducing them, so such a dramatic centralization shouldn’t be acceptable for a power user. Luckily, decades-old technologies like RSS feeds can come to the rescue, allowing us to tune what we want to read and build automation pipelines that distribute the content wherever and whenever we like.

Also, e-readers are becoming more and more pervasive, thanks also to the drop in the price of e-ink displays in the last few years and to more companies and products entering the market. Automating the delivery of web content to e-readers can really create a new and more comfortable way to stay informed — and helps us find another great use case for our Kindle, other than downloading novels to read on the beach.

Reactions

How to interact with this page

Webmentions

To interact via Webmentions, send an activity that references this URL from a platform that supports Webmentions, such as Lemmy, WordPress with Webmention plugins, or any IndieWeb-compatible site.

ActivityPub

  • Follow @blog@platypush.tech on your ActivityPub platform (e.g. Mastodon, Misskey, Pleroma, Lemmy).
  • Mention @blog@platypush.tech in a post to feature on the Guestbook.
  • Search for this URL on your instance to find and interact with the post.
  • Like, boost, quote, or reply to the post to feature your activity here.
📣 1 🔗 1
Fabio Manganiello
I’ve always been a supporter of well-curated newsletters. They give me an opportunity to get a good overview of what happened in the fields I follow within a span of a day, a week or a month. However, not all the newsletters fit this category. Some don’t think three times before selling email addresses to 3rd-parties — and within the blink of an eye your mailbox can easily get flooded with messages that you didn’t request. Others may sign up your address for other services or newsletters as well, and often they don’t often much granularity to configure which communications you want to receive. Even in the best-case scenario, the most privacy-savvy user may still think twice before signing up for a newsletter — you’re giving your personal email address to someone else you don’t necessarily trust, implying “yes, this is my address and I’m interested in this subject”. Additionally, most of the newsletters spice up their URLs with tracking parameters, so they can easily measure user engagement — something you may not necessarily be happy with. Moreover, the customization junkie may also have a valid use case for a more finely tuned selection of content in his newsletter — you may want to group some sources together into the same daily/weekly email, or you may be interested only in some particular subset of the subjects covered by a newsletter, filtering out those that aren’t relevant, or customize the style of the digest that gets delivered. Finally, a fully automated way to deliver newsletters through 5 lines of code and the tuning of a couple of parameters is the nirvana for many companies of every size out there. Feed up the newsletter Those who read my articles in the past may know that I’m an avid consumer of RSS feeds. Despite being a 21-year-old technology, they do their job very well when it comes to deliver the information that matters without all the noise and trackers, and they provide a very high level of integration being simple XML documents. However, in spite of all the effort I put to be up-to-date with all my sources, a lot of potentially interesting content inevitably slips through — and that’s where newsletters step in, as they filter and group together all the content that was generated in a given time frame and periodically deliver it to your inbox. My ideal solution would be something that combines the best aspects of both the worlds: the flexibility of an RSS subscription, combined with a flexible way of filtering and aggregating content and sources, and get the full package delivered at my door in whichever format I like (HTML, PDF, MOBI…). In this article I’m going to show how to achieve this goal with a few tools: One or more sources that you want to track and that support RSS feeds (in this example I’ll use the MIT Technology Review RSS feed, but the procedure works for any RSS feed). An email address. Platypush to do the heavy-lifting job — monitor the RSS sources at custom intervals, trigger events when a source has some new content, create a digest out of the new content, and deliver the full package to a list of email addresses. Let’s cover these points step by step. Installing and configuring Platypush We’ll be using the http.poll backend configured with one or more RssUpdate objects to poll our RSS sources at regular intervals and create the digests, and either the mail.smtp plugin or the google.mail plugin to send the digests to our email. You can install Platypush on any device where you want to run your logic — a RaspberryPi, an old laptop, a cloud node, and so on. We will install the base package with the rss module. Optionally, you can install it with the pdf module as well (if you want to export your digests also to PDF) or the google module (if you want to send the newsletter from a GMail address instead of an SMTP server). The first option is to install the latest stable version through pip: [sudo] pip install 'platypush[rss,pdf,google]' The other option is to install the latest git version: git clone https://git.platypush.tech/platypush/platypush cd platypush [sudo] pip install '.[rss,pdf,google]' Monitoring your RSS feeds Once the software is installed, create the configuration file ~/.config/platypush/config.yaml if it doesn't exist already and add the configuration for the RSS monitor: # Generic HTTP endpoint monitor backend.http.poll: requests: # Add a new RSS feed to the pool - type: platypush.backend.http.request.rss.RssUpdates # URL to the RSS feed url: https://www.technologyreview.com/feed/ # Title of the feed (shown in the head of the digest) title: MIT Technology Review # How often we should monitor this source (24*60*60 secs = once a day) poll_seconds: 86400 # Format of the digest (HTML or PDF) digest_format: html You can also add more sources to the http.poll requests object, each with its own configuration. Also, you can customize the style of your digest by passing some valid CSS to these configuration attributes: # Style of the body element body_style: 'font-size: 20px; font-family: "Merriweather", Georgia, "Times New Roman", Times, serif' # Style of the main title title_style: 'margin-top: 30px' # Style of the subtitle subtitle_style: 'margin-top: 10px; page-break-after: always' # Style of the article titles article_title_style: 'font-size: 1.6em; margin-top: 1em; padding-top: 1em; border-top: 1px solid #999' # Style of the article link article_link_style: 'color: #555; text-decoration: none; border-bottom: 1px dotted font-size: 0.8em' # Style of the article content article_content_style: 'font-size: 0.8em' The digest_format attribute determines the output format of your digest - you may want to choose html if you want to deliver a summary of the articles in a newsletter, or pdf if you want instead to deliver the full content of each item as an attachment to an email address. Bonus point: since you can send PDFs to a Kindle if you configured an email address, this mechanism allows you to deliver the full digest of your RSS feeds to your Kindle's email address. The RssUpdates object also provides native integration with the Mercury Parser API to automatically scrape the content of a web page - I covered some of these concepts in my previous article on how to parse RSS feeds and send the PDF digest to your e-reader. The same mechanism works well for newsletters too. If you want to parse the content of the newsletter as well, all you have to do is configure the http.webpage Platypush plugin. Since the Mercury API doesn't provide a Python binding, this requires a couple of JavaScript dependencies: # Install Node and NPM, e.g. on Debian: apt-get install nodejs npm # Install the Mercury Parser API npm install [-g] @postlight/mercury-parser # Make sure that the Platypush PDF module dependencies # are installed if you plan HTML->PDF conversion pip install 'platypush[pdf]' Then, if you want to parse the full content of the items and generate a PDF digest out of them, change your http.poll configuration to something like this: backend.http.poll: requests: - type: platypush.backend.http.request.rss.RssUpdates url: https://www.technologyreview.com/feed/ title: MIT Technology Review poll_seconds: 86400 # PDF digest format digest_format: pdf # Extract the full content of the items extract_content: True WARNING: Extracting the full content of the articles in an RSS feed has two limitations — a practical one and a legal one: Some websites may require user login before displaying the full content of an article. Some websites perform such checks client-side — and the parser API can usually circumvent them, especially if the full content of an article is actually just hidden behind a client-side paywall. Some websites, however, implement their user checks server-side too before sending the content to the client — and in those cases the parser API may return only a part of the content or no content at all. Always keep in mind that parsing the full content of an article behind a paywall may represent a violation of intellectual property under some jurisdictions, so make sure to do it only for content that is either free or that you have to permission to scrape. Configuring the mail delivery When new content is published on a subscribed RSS feed Platypush will generate a NewFeedEvent and it should create a copy of the digest under ~/.local/share/platypush/feeds/cache/{date:time}_{feed-title}.[html|pdf]. The NewFeedEvent in particular is the link you need to create your custom logic that sends an email to a list of addresses when new content is available. First, configure the Platypush mail plugin you prefer. When it comes to sending emails you primarily have two options: The mail.smtp plugin — if you want to send emails directly through an SMTP server. Platypush configuration:mail.smtp: username: you@gmail.com password: your-pass server: smtp.gmail.com port: 465 ssl: True The google.mail plugin — if you want to use the native GMail API to send emails. If that is the case then first make sure that you have the dependencies for the Platypush Google module installed:[sudo] pip install 'platypush[google]' In this case you’ll also have to create a project on the Google Developers console and download the OAuth credentials: Click on “Credentials” from the context menu > OAuth Client ID. Once generated, you can see your new credentials in the “OAuth 2.0 client IDs” section. Click on the “Download” icon to save them to a JSON file. Copy the file to your Platypush device/server under e.g. ~/.credentials/google/client_secret.json. Run the following command on the device to authorize the application: python -m platypush.plugins.google.credentials \ "https://www.googleapis.com/auth/gmail.modify" \ ~/.credentials/google/client_secret.json \ --noauth_local_webserver At this point the GMail delivery is ready to be used by your Platypush automation. Connecting the dots Now that both the RSS parsing logic and the mail integration are in place, we can glue them together through the NewFeedEvent event. The new advised way to configure events in Platypush is through native Python scripts - the custom YAML-based syntax for events and procedure was becoming too cumbersome to maintain and write (although it’s still supported), and I feel like going back to a clean and simple Python API may be a better option. Create and initialize the Platypush scripts directory, if it doesn’t exist already: mkdir -p ~/.config/platypush/scripts cd ~/.config/platypush/scripts # Make sure that the scripts module is initialized touch __init__.py Then, create a new hook on NewFeedEvent: $EDITOR rss_news.py import os from typing import List from platypush.event.hook import hook from platypush.message.event.http.rss import NewFeedEvent from platypush.utils import run # Path to your mailing list - a text file with one address per line maillist = os.path.expanduser('~/.mail.list') def get_addresses() -> List[str]: with open(maillist, 'r') as f: return [addr.strip() for addr in f.readlines() if addr.strip() and not addr.strip().startswith('#')] # This hook matches: # - event_type=NewFeedEvent # - digest_format='html' # - source_title='MIT Technology Review' @hook(NewFeedEvent, digest_format='html', source_title='MIT Technology Review') def send_mit_rss_feed_digest(event: NewFeedEvent, **_): # The digest output file is stored in event.args['digest_filename'] with open(event.args['digest_filename'], 'r') as f: run(action='mail.smtp.send', from_='you@yourdomain.com', to=get_addresses(), subject=f'{event.args.get("source_title")} feed digest', body=f.read(), body_type='html') # Or, if you opted for the native GMail plugin you may want to go for: @hook(NewFeedEvent, digest_format='html', source_title='MIT Technology Review') def send_mit_rss_feed_digest(event: NewFeedEvent, **_): # The digest output file is stored in event.args['digest_filename'] with open(event.args['digest_filename'], 'r') as f: run(action='google.mail.compose', sender='you@gmail.com', to=get_addresses(), subject=f'{event.args.get("source_title")} feed digest', body=f.read()) # If instead you want to send the digest in PDF format as an attachment: @hook(NewFeedEvent, digest_format='html', source_title='MIT Technology Review') def send_mit_rss_feed_digest(event: NewFeedEvent, **_): # mail.smtp plugin case run(action='mail.smtp.send', from_='you@yourdomain.com', to=get_addresses(), subject=f'{event.args.get("source_title")} feed digest', body='', attachments=[event.args['digest_filename']]) # google.mail case run(action='google.mail.compose', sender='you@gmail.com', to=get_addresses(), subject=f'{event.args.get("source_title")} feed digest', body='', files=[event.args['digest_filename']]) Finally, create your ~/.mail.list file with one destination email address per line and start platypush either from the command line or as a service. You should receive your email with the first batch of articles shortly after startup, and you'll receive more items if a new batch is available after the poll_seconds configured period.