{"id":48653078,"url":"https://github.com/shantanugoel/email-actions","last_synced_at":"2026-04-10T08:55:42.947Z","repository":{"id":57426109,"uuid":"85428169","full_name":"shantanugoel/email-actions","owner":"shantanugoel","description":"email-actions is a tiny SMTP server with a rules based engine to trigger any actions (notifications/commands etc) based on the emails sent to this server","archived":false,"fork":false,"pushed_at":"2017-04-03T13:29:27.000Z","size":55,"stargazers_count":35,"open_issues_count":2,"forks_count":9,"subscribers_count":4,"default_branch":"master","last_synced_at":"2026-04-10T08:55:39.258Z","etag":null,"topics":["aiosmtpd","asyncio","email","ifttt","join","notifications","smtp"],"latest_commit_sha":null,"homepage":"https://shantanugoel.com/2017/04/03/email-actions-trigger-tasks-from-email-smtp-server/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shantanugoel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-03-18T19:54:07.000Z","updated_at":"2026-02-19T20:47:39.000Z","dependencies_parsed_at":"2022-09-11T05:01:19.831Z","dependency_job_id":null,"html_url":"https://github.com/shantanugoel/email-actions","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/shantanugoel/email-actions","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shantanugoel%2Femail-actions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shantanugoel%2Femail-actions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shantanugoel%2Femail-actions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shantanugoel%2Femail-actions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shantanugoel","download_url":"https://codeload.github.com/shantanugoel/email-actions/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shantanugoel%2Femail-actions/sbom","scorecard":{"id":816136,"data":{"date":"2025-08-11","repo":{"name":"github.com/shantanugoel/email-actions","commit":"6570eb90922079de1f7cd0915d6fcbe364d27867"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.9,"checks":[{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":1,"reason":"9 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2024-221 / GHSA-pr2m-px7j-xg65","Warn: Project is vulnerable to: GHSA-wgjv-9j3q-jhg8","Warn: Project is vulnerable to: PYSEC-2021-142 / GHSA-8q59-q68h-6hv4","Warn: Project is vulnerable to: PYSEC-2018-49 / GHSA-rprw-h62v-c2w7","Warn: Project is vulnerable to: PYSEC-2014-14 / GHSA-652x-xj99-gmcc","Warn: Project is vulnerable to: GHSA-9hjg-9r4m-mvj7","Warn: Project is vulnerable to: GHSA-9wx4-h78v-vm56","Warn: Project is vulnerable to: PYSEC-2014-13 / GHSA-cfj3-7x9c-4p3h","Warn: Project is vulnerable to: PYSEC-2018-28 / GHSA-x84v-xcm2-53pg"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-23T14:18:42.189Z","repository_id":57426109,"created_at":"2025-08-23T14:18:42.189Z","updated_at":"2025-08-23T14:18:42.189Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31635969,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T07:40:12.752Z","status":"ssl_error","status_checked_at":"2026-04-10T07:40:11.664Z","response_time":98,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aiosmtpd","asyncio","email","ifttt","join","notifications","smtp"],"created_at":"2026-04-10T08:55:42.227Z","updated_at":"2026-04-10T08:55:42.853Z","avatar_url":"https://github.com/shantanugoel.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Table Of Contents\n\n- [email-actions](#email-actions)\n- [Why did you make email-actions](#why-did-you-make-email-actions)\n- [What are the benefits/differences compared to hosted services like IFTTT](#what-are-the-benefits-differences-compared-to-hosted-services-like-ifttt)\n- [Current high level feature list](#current-high-level-feature-list)\n- [Installation](#installation)\n- [Usage](#usage)\n  * [Config file format](#config-file-format)\n  * [Rules](#rules)\n  * [Plugin settings](#plugin-settings)\n- [Contributing](#contributing)\n  * [How to write a plugin](#how-to-write-a-plugin)\n  \n# email-actions\nemail-actions is a tiny SMTP server with a rules based engine to trigger any actions (notifications/commands etc) based on the emails sent to this server.\nThink of it like [IFTTT](https://ifttt.com) but where input trigger is email and can be set up and run locally as well.\n\n# Why did you make email-actions\nLike most of my projects, email-actions is a 'scratch-your-own-itch' project. I bought a NAS (Synology ds216j) which also doubled as a downloader of anime/tv shows etc through RSS using its inbuilt \"Download Station\" app. I also used Plex to watch them over the network but these needed to be moved to a proper folder and named in a specific format (and some crap deleted and other maintenance done or sometimes some post processing done) to have Plex display/play them properly. I used Filebot and a few custom scripts for this but had to either do this manually or use a fixed time task scheduling (which tended to delay watching). This was semi-irritating. \nI also wanted to know when something had been downloaded so I could binge on that latest episode as soon as it was done :)\nDownload station had a hack (by changing internal files) to run custom script after a download was completed but it had to be redone after every firmware update and sometimes, after every restart. And finally it stopped working altogether with recent updates.\n\nIt did support email notifications though. Thus email-actions was born. So I could push notifications for downloaded items run my custom scripts on the downloaded items.\n\nSince then, I've started using it for many other things as email is pervasive and most of the devices support email based notifications. So I can trap them and carry out other actions.\n\n# What are the benefits/differences compared to hosted services like IFTTT\nIFTTT provides email hooks as well. I *think* email-actions may be an alternative (you can decide whether it's better or not) with respect to below:\n- IFTTT works as a client once email is received so you still need an available SMTP server to be able to send email. This can be expensive or risky as you'd have to share your server username/pwd to the email sending entity. email-actions is an SMTP server that takes actions before any actual email delivery.\n- Can be run locally with minimal dependencies. You don't need to send your data to internet or even have an internet connection\n- Tiny footprint\n- Can run local commands as well while IFTTT still needs to be integrated with something else if that's what you need\n- You are in control of your info\n- Free(er), that is, no limitations on hooks/conditions etc\n\n# Current high level feature list\n- aiosmtpd based for aync email processing for performance\n- The action execution is also asyncio based, so will free up the email sender while processing the action in background\n- Easy yaml based configuration\n- Global or local variables for full customization/reuse\n- Action decision based on \"To\" email address filtering (Addition of many other filters on the roadmap)\n- Plugins supported:\n  - [Join](https://joaoapps.com/join/) push notifications (Will add pushbullet if there's a demand or can use custom external script for now)\n  - Custom Local commands (Any arguments, any script type, custom environment variables)\n  - Email (Can forward the email to custom upstream servers further if needed for more actions or actual email delivery)\n\n# Installation\n\nPre-requisites: You need Python 3.4+ to be able to run this\n\n- Install using pip (May need to use `pip3` instead of `pip` according to your OS/python installation. May need to use `sudo` prefix before below command if installing system wide)\n\n`pip install email-actions` \n\n- Install directly\n\n```\ngit clone git@github.com:shantanugoel/email-actions.git\ncd email-actions\npython setup.py install\n```\n\n# Usage\n\n```\nusage: email_actions [-h] [-v] [-H HOSTNAME] [-p PORT] [-l LOG] -c CONFIG\n\noptional arguments:\n  -h, --help            show this help message and exit\n  -v, --version         show program's version number and exit\n  -H HOSTNAME, --hostname HOSTNAME\n                        Host IP or name to bind the server to\n  -p PORT, --port PORT  Port number to bind the server to\n  -l LOG, --log LOG     Set log level. 0=\u003e Warning, 1=\u003eInfo, 2=\u003eDebug\n\nrequired arguments:\n  -c CONFIG, --config CONFIG\n                        Specify config file (yaml format) to be used. If it\n                        doesn't exist, we'll try to create it\n\n```\n\nExamples:\n```\nemail_actions -H 127.0.0.1 -p 8500 -l 2 -c /home/shantanu/email_actions_cfg.yml\n```\n```\nemail_actions -c /home/shantanu/email_actions_cfg.yml\n```\n\nMost of the options above are self explanatory. If you don't specify a hostname, it will choose `localhost` by default. If you don't specify a port, it'll choose `8025` by default. \n\n**Note** I recommend running the server on localhost or an internal network interface so that it can't be abused from internet. Right now it doesn't support authentication (limitation of aiosmtpd. Will be fixed soon), so if you must open it up to the internet, add your own scheme of verification either through a randomly generated email address in \"To\" rule or some other check in subject/content in your own external script that you are triggering.\n\nSpecifying a config file is mandatory. If the specified file doesn't exist, we'll generate a dummy one which you can fill. But essentially this is a step that you can't avoid. The config file is explained in more detail below.\n\n## Config file format\n\nemail-actions uses the simple `yaml` format for its configuration. Learning this is a small task (few minutes at most for the basic usage that we need). You can look at [this page](https://learn.getgrav.org/advanced/yaml) for a quick reference.\n\nemail-actions works on the basis of user specified `filters`. Each filter can have `rules` specified which decide whether to run an action or not on the incoming email. Each filter also specifies `actions` (which is 1 or more plugins) to run an action on the incoming email if it passes the `rules`.\n\nAt least 1 filter is necessary in the configuration. Each filter must have at least 1 action. Rest all is optional. Each action plugin may have it's own mandatory OR optional settings. See [Plugin Settings](#plugin-settings) for all available plugins and their options/variables\n\nThe config file has the following general format. All text after `#` is an explanation, not a part of the config itself.\n\nNames within `\u003c\u003e` can be substituted by user as per their choice. Names outside `\u003c\u003e` are reserved by email-actions and must be used as is.\n\nAll settings are case-sensitive. So take care of that.\n\n```\nglobal:  # Optional keyword that specifies global variables for plugins. These are available in all instances of your plugins in each filter\n  \u003cplugin_name\u003e:  # Plugin name for which you are specifying a global variable\n    \u003csetting_1\u003e: \u003cabcd\u003e # Variable/setting for this plugin.\n    \u003csetting_2\u003e: \u003cefgh\u003e # Variable/setting for this plugin.\n\nfilters: #Mandatory keyword to signify start of your filters specifications.\n  \u003cfilter_name\u003e: # User specified name for a filter\n    rules:       # Rules specifications start\n      to: \u003cemail_id\u003e # A rule that matches\n```\n\nExample: Take a look at the below sample config (Also found in [this location](https://github.com/shantanugoel/email-actions/blob/master/sample/config.yml)) \n\n```\n# Specify a global variable for join plugin's api key\nglobal:\n  join:\n    apikey: my_join_app_api_key\n\n# Specify 2 filters.\n# my_filter matches only the emails which are sent to abc@a.com and runs below 2 actions:\n## Send join push notification using the global join api key\n## Send an email using the credentials specified\n# my_second_filter runs on all emails since there is no rule specified\n# It runs below 2 actions:\n## Send join notification using another_api_key. Local variable overrides the global one\n## Run external command with given args and also sets up a environment variable called \"MY_ENV_VAR\" which can be accessed in external command\n\nfilters:\n  my_filter:\n    rules:\n      to: abc@a.com\n    actions:\n      join:\n      email:\n        host: smtp.example.com\n        username: my_email_username\n        password: my_email_password\n        port: 587\n        secure: True\n  my_second_filter:\n      join:\n        apikey: another_api_key\n      exec:\n        cmd: /home/shantanu/test.sh\n        args:\n          - /home/shantanu/abc_file\n          - another_arg\n        env:\n          MY_ENV_VAR: 'Some Value'\n\n```\n\n## Rules\nCurrently, below rules are supported. These can be specified under a `rules` block.\n\n\n| Rule Keyword | Value                                                                        |\n|--------------|------------------------------------------------------------------------------|\n| to           | Any email id which should exactly match the \"To\" field in the incoming email |\n\n## Plugin Settings\n\n### join\n\nThis plugin sends a push notification to your devices using the [Join](https://joaoapps.com/join/) app\n\nOptions:\n\n\n| Option Keyword | Mandatory / Optional | Default Value | Comment                                                     |\n|----------------|----------------------|---------------|-------------------------------------------------------------|\n| apikey         | Mandatory            | None          | Your API key from [here](https://joinjoaomgcd.appspot.com/) |\n| deviceId       | Optional             | group.all     | See valid options [here](https://joaoapps.com/join/api/)    |\n| title          | Optional             | Email Subject | See valid options [here](https://joaoapps.com/join/api/)    |\n| text           | Optional             | Email content | See valid options [here](https://joaoapps.com/join/api/)    |\n\n### exec\n\nThis plugin allows to run any arbitrary command or script on your local system on which email-actions server is running.\n\n\n| Option Keyword | Mandatory / Optional | Default Value    | Comment                                                                                          |\n|----------------|----------------------|------------------|--------------------------------------------------------------------------------------------------|\n| cmd            | Mandatory            | None             | Full path to the command to be run. Don't include arguments. Enclose in quotes if space in path  |\n| args           | Optional             | Empty list       | List of arguments to be passed to command, 1 on each line.                                       |\n| env            | Optional             | Empty dictionary | Key value pair of custom environment variables for the external command/script. One on each line |\n\n### email\n\nThis plugin allows to forward the incoming email further to an upstream smtp server\n\n\n| Option Keyword | Mandatory / Optional | Default Value | Comment                                                          |\n|----------------|----------------------|---------------|------------------------------------------------------------------|\n| host           | Mandatory            | None          | Provide hostname or ip of your upstream smtp server              |\n| port           | Optional             | 25            | Port for upstream smtp server                                    |\n| username       | Optional             | None          | username if required                                             |\n| password       | Optional             | None          | Password if required                                             |\n| secure         | Optional             | False         | Set it to true if upstream server requires secure/TLS connection |\n\n# Contributing\nFeel free to fork the repo and send PRs for any changes. If you can't make changes but want to report issues or provide feedback, open an Issue on github or ping me on twitter [@shantanugoel](https://twitter.com/shantanugoel)\n\nYou can contribute either to the core or write a plugin for your usecase. The only guiding principle is to keep it as simple/minimal as possible.\n\n## How to write a plugin\nTake a look at any plugin in [plugins](https://github.com/shantanugoel/email-actions/tree/master/email_actions/plugins) directory\nA minimal plugin needs to do following things:\n- Define 'PLUGIN_NAME'. This need not be same as the file name but is preferred to keep that way\n- A function that takes these parameters: `filter_name, msg_from, msg_to, msg_subject, msg_content` and doesn't return anything\n- Read plugin's configuration (if any) using email_actions.config.read_config_plugin function\n  - Ideally the plugin should not need to use any other function from the core\n- After writing the plugin, add the plugin's name and entry function in `entry_funcs` dict in [plugins init file](https://github.com/shantanugoel/email-actions/tree/master/email_actions/plugins/__init__.py)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshantanugoel%2Femail-actions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshantanugoel%2Femail-actions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshantanugoel%2Femail-actions/lists"}