{"id":13815419,"url":"https://github.com/samuraisam/pyapns","last_synced_at":"2025-10-30T04:02:13.441Z","repository":{"id":771414,"uuid":"456545","full_name":"samuraisam/pyapns","owner":"samuraisam","description":"An APNS provider with multi-app support.","archived":false,"fork":false,"pushed_at":"2017-04-17T08:18:01.000Z","size":551,"stargazers_count":2027,"open_issues_count":26,"forks_count":224,"subscribers_count":92,"default_branch":"master","last_synced_at":"2025-05-04T08:27:00.447Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/samuraisam.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.txt","contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2010-01-03T01:45:30.000Z","updated_at":"2025-04-22T09:17:29.000Z","dependencies_parsed_at":"2022-08-16T10:50:26.999Z","dependency_job_id":null,"html_url":"https://github.com/samuraisam/pyapns","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samuraisam%2Fpyapns","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samuraisam%2Fpyapns/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samuraisam%2Fpyapns/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samuraisam%2Fpyapns/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/samuraisam","download_url":"https://codeload.github.com/samuraisam/pyapns/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254313759,"owners_count":22050096,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-08-04T04:03:28.799Z","updated_at":"2025-10-30T04:02:13.348Z","avatar_url":"https://github.com/samuraisam.png","language":"Python","readme":"pyapns\n======\n\nA universal Apple Push Notification Service (APNS) provider.\n\nFeatures:\n\u003cul\u003e\n  \u003cli\u003eXML-RPC Based, works with any client in any language\u003c/li\u003e\n  \u003cli\u003eNative Python API with Django and Pylons support\u003c/li\u003e\n  \u003cli\u003eNative Ruby API with Rails/Rack support\u003c/li\u003e\n  \u003cli\u003eScalable, fast and easy to distribute behind a proxy\u003c/li\u003e\n  \u003cli\u003eBased on Twisted\u003c/li\u003e\n  \u003cli\u003eMulti-application and dual environment support\u003c/li\u003e\n  \u003cli\u003eSimplified feedback interface\u003c/li\u003e\n\u003c/ul\u003e\n\npyapns is an APNS provider that you install on your server and access through XML-RPC. To install you will need Python, [Twisted](http://pypi.python.org/pypi/Twisted) and [pyOpenSSL](http://pypi.python.org/pypi/pyOpenSSL). It's also recommended to install [python-epoll](http://pypi.python.org/pypi/python-epoll/) for best performance (if epoll is not available, like on Mac OS X, you may want to use another library, like [py-kqueue](http://pypi.python.org/pypi/py-kqueue/2.0.1)). If you like easy_install try (it should take care of the dependancies for you):\n\n    $ sudo easy_install pyapns\n    \npyapns is a service that runs persistently on your machine. To start it:\n\n    $ twistd -r epoll web --class=pyapns.server.APNSServer --port=7077\n\nThis will create a `twistd.pid` file in your current directory that can be used to kill the process. `twistd` is a launcher used for running network persistent network applications. It takes many more options that can be found by running `man twistd` or using a [web man page](http://linux.die.net/man/1/twistd).\n\nTo get started right away, use the included client:\n\n    $ python\n    \u003e\u003e\u003e from pyapns import configure, provision, notify\n    \u003e\u003e\u003e configure({'HOST': 'http://localhost:7077/'})\n    \u003e\u003e\u003e provision('myapp', open('cert.pem').read(), 'sandbox')\n    \u003e\u003e\u003e notify('myapp', 'hexlified_token_str', {'aps':{'alert': 'Hello!'}})\n\n### The Multi-Application Model\npyapns supports multiple applications. Before pyapns can send notifications, you must first provision the application with an Application ID, the environment (either 'sandbox' or 'production') and the certificate file. The `provision` method takes 4 arguments, `app_id`, `path_to_cert_or_cert`, `environment` and `timeout`. A connection is kept alive for each application provisioned for the fastest service possible. The application ID is an arbitrary identifier and is not used in communication with the APNS servers.\n\nWhen a connection can not be made within the specified `timeout` a timeout error will be thrown by the server. This usually indicates that the wrong [type of] certification file is being used, a blocked port or the wrong environment.\n\nAttempts to provision the same application id multiple times are ignored.\n\n### Sending Notifications\nCalling `notify` will send the message immediately if a connection is already established. The first notification may be delayed a second while the server connects. `notify` takes `app_id`, `token_or_token_list` and `notification_or_notification_list`. Multiple notifications can be batched for better performance by using paired arrays of token/notifications. When performing batched notifications, the token and notification arrays must be exactly the same length.\n\nThe full notification dictionary must be included as the notification:\n\n    {'aps': {\n        'sound': 'flynn.caf',\n        'badge': 0,\n        'message': 'Hello from pyapns :)'\n      }\n    } # etc...\n\n### Retrieving Inactive Tokens\nCall `feedback` with the `app_id`. A list of tuples will be retrieved from the APNS server that it deems inactive. These are returned as a list of 2-element lists with a `Datetime` object and the token string.\n\n### XML-RPC Methods\nThese methods can be called on the server you started the server on. Be sure you are not including `/RPC2` in the URL.\n\n### provision\n\n      Arguments\n          app_id        String            the application id for the provided\n                                          certification\n          cert          String            a path to a .pem file or the a\n                                          string with the entie file\n          environment   String            the APNS server to use - either\n                                          'production' or 'sandbox'\n          timeout       Integer           timeout for connection attempts to\n                                          the APS servers\n      Returns\n          None\n\n### notify\n\n      Arguments\n          app_id        String            the application id to send the\n                                          message to\n          tokens        String or Array   an Array of tokens or a single\n                                          token string\n          notifications String or Array   an Array of notification\n                                          dictionaries or a single\n                                          notification dictionary\n      \n      Returns\n          None\n\n### feedback\n\n      Arguments\n          app_id        String            the application id to retrieve\n                                          retrieve feedback for\n      \n      Returns\n          Array(Array(Datetime(time_expired), String(token)), ...)\n          \n\n### The Python API\npyapns also provides a Python API that makes the use of pyapns even simpler. The Python API must be configured before use but configuration files make it easier. The pyapns `client` module currently supports configuration from Django settings and Pylons config. To configure using Django, the following must be present in  your settings file:\n\n    PYAPNS_CONFIG = {\n      'HOST': 'http://localhost:8077/',\n      'TIMEOUT': 15,                    # OPTIONAL, host timeout in seconds\n      'INITIAL': [                      # OPTIONAL, see below\n        ('craigsfish', '/home/samsutch/craigsfish/apscert.pem', 'sandbox'),\n      ]\n    }\n\nOptionally, with Django settings, you can skip manual provisioning by including a list of `(name, path, environment)` tuples that are guaranteed to be provisioned by the time you call `notify` or `feedback`.\n\nConfiguring for pylons is just as simple, but automatic provisioning isn't possible, in your configuration file include:\n\n    pyapns_host = http://localhost:8077/\n    pyapns_timeout = 15\n\nFor explanations of the configuration variables see the docs for `pyapns.client.configure`.\n\nEach of these functions can be called synchronously and asynchronously. To make them perform asynchronously simply supply a callback and pass `async=True` to the function. The request will then be made in another thread and your callback will be executed with the results. When calling asynchronously no value will be returned:\n\n    def got_feedback(tuples):\n      trim_inactive_tokens(tuples)\n    feedback('myapp', async=True, callback=got_feedback)\n\n### `pyapns.client.configure(opts)`\n\n    Takes a dictionary of options and configures the client. \n    Currently configurable options are 'HOST', 'TIMEOUT' and 'INITIAL' \n    the latter of which is only read once.\n    \n    Config Options:\n        HOST        - A full host name with port, ending with a forward slash\n        TIMEOUT     - An integer specifying how many seconds to timeout a\n                      connection to the pyapns server (prevents deadlocking\n                      the parent thread).\n        INITIAL     - A List of tuples to be supplied to provision when\n                      the first configuration happens.\n\n### `pyapns.client.provision(app_id, path_to_cert_or_cert, environment, timeout=15, async=False, callback=None, errback=None)`\n\n    Provisions the app_id and initializes a connection to the APNS server.\n    Multiple calls to this function will be ignored by the pyapns daemon\n    but are still sent so pick a good place to provision your apps, optimally\n    once.\n    \n    Arguments:\n        app_id                 the app_id to provision for APNS\n        path_to_cert_or_cert   absolute path to the APNS SSL cert or a \n                               string containing the .pem file\n        environment            either 'sandbox' or 'production'\n        timeout                number of seconds to timeout connection\n                               attempts to the APPLE APS SERVER\n        async                  pass something truthy to execute the request in a \n                               background thread\n        callback               a function to be executed with the result\n        errback                a function to be executed with the error in case of an error\n\n    Returns:\n        None\n\n### `pyapns.client.notify(app_id, tokens, notifications, async=False, callback=None, errback=None)`\n\n    Sends push notifications to the APNS server. Multiple \n    notifications can be sent by sending pairing the token/notification\n    arguments in lists [token1, token2], [notification1, notification2].\n    \n    Arguments:\n        app_id                 provisioned app_id to send to\n        tokens                 token to send the notification or a \n                               list of tokens\n        notifications          notification dict or a list of notification dicts\n        async                  pass something truthy to execute the request in a \n                               background thread\n        callback               a function to be executed with the result when done\n        errback                a function to be executed with the error in case of an error\n\n      Returns:\n          None\n\n### `pyapns.client.feedback(app_id, async=False, callback=None, errback=None)`\n\n    Retrieves a list of inactive tokens from the APNS server and the times\n    it thinks they went inactive.\n    \n    Arguments:\n        app_id                 the app_id to query\n        async                  pass something truthy to execute the request in \n                               a background thread\n        callback               a function to be executed with the result when \n                               feedbacks are done fetching\n        errback                a function to be executed with the error if there\n                               is one during the request\n\n    Returns:\n        List of feedback tuples like [(datetime_expired, token_str), ...]\n\n\n## The Ruby API\n\n### PYAPNS::Client\nThere's python in my ruby!\n\nThe ruby gem can be installed from [here](https://github.com/krasio/pyapns_gem)\n\nThis is a class used to send notifications, provision applications and\nretrieve feedback using the Apple Push Notification Service.\n\nPYAPNS is a multi-application APS provider, meaning it is possible to send\nnotifications to any number of different applications from the same application\nand same server. It is also possible to scale the client to any number\nof processes and servers, simply balanced behind a simple web proxy.\n\nIt may seem like overkill for such a bare interface - after all, the \nAPS service is rather simplistic. However, PYAPNS takes no shortcuts when it\ncomes to completeness/compliance with the APNS protocol and allows the\nuser many optimization and scaling vectors not possible with other libraries.\nNo bandwidth is wasted, connections are persistent and the server is\nasynchronous therefore notifications are delivered immediately.\n\nPYAPNS takes after the design of 3rd party push notification service that\ncharge a fee each time you push a notification, and charge extra for so-called\n'premium' service which supposedly gives you quicker access to the APS servers.\nHowever, PYAPNS is free, as in beer and offers more scaling opportunities without\nthe financial draw.\n\n### Provisioning\n\nTo add your app to the PYAPNS server, it must be `provisioned` at least once.\nNormally this is done once upon the start-up of your application, be it a web\nservice, desktop application or whatever... It must be done at least once\nto the server you're connecting to. Multiple instances of PYAPNS will have\nto have their applications provisioned individually. To provision an application\nmanually use the `PYAPNS::Client#provision` method.\n\n    require 'pyapns'\n    client = PYAPNS::Client.configure\n    client.provision :app_id =\u003e 'cf', :cert =\u003e '/home/ss/cert.pem', :env =\u003e 'sandbox', :timeout =\u003e 15\n\nThis basically says \"add an app reference named 'cf' to the server and start\na connection using the certification, and if it can't within 15 seconds, \nraise a `PYAPNS::TimeoutException`\n\nThat's all it takes to get started. Of course, this can be done automatically\nby using PYAPNS::ClientConfiguration middleware. `PYAPNS::Client` is a singleton\nclass that is configured using the class method `PYAPNS::Client#configure`. It\nis sensibly configured by default, but can be customized by specifying a hash\nSee the docs on `PYAPNS::ClientConfiguration` for a list of available configuration\nparameters (some of these are important, and you can specify initial applications)\nto be configured by default.\n\n### Sending Notifications\n\nOnce your client is configured, and application provisioned (again, these\nshould be taken care of before you write notification code) you can begin\nsending notifications to users. If you're wondering how to acquire a notification\ntoken, you've come to the wrong place... I recommend using google. However,\nif you want to send hundreds of millions of notifications to users, here's how\nit's done, one at a time...\n\nThe `PYAPNS::Client#notify` is a sort of polymorphic method which can notify\nany number of devices at a time. It's basic form is as follows:\n\n    client.notify 'cf', 'long ass app token', {:aps=\u003e {:alert =\u003e 'hello?'}}\n\nHowever, as stated before, it is sort of polymorphic:\n\n    client.notify 'cf', ['token', 'token2', 'token3'], [alert, alert2, alert3]\n   \n    client.notify :app_id =\u003e 'cf', :tokens =\u003e 'mah token', :notifications =\u003e alertHash\n\n    client.notify 'cf', 'token', PYAPNS::Notification('hello tits!')\n\nAs you can see, the method accepts paralell arrays of tokens and notifications\nmeaning any number of notifications can be sent at once. Hashes will be automatically\nconverted to `PYAPNS::Notification` objects so they can be optimized for the wire\n(nil values removed, etc...), and you can pass `PYAPNS::Notification` objects\ndirectly if you wish.\n\n### Retrieving Feedback\n\nThe APS service offers a feedback functionality that allows application servers\nto retrieve a list of device tokens it deems to be no longer in use, and the\ntime it thinks they stopped being useful (the user uninstalled your app, better\nluck next time...) Sounds pretty straight forward, and it is. Apple recommends\nyou do this at least once an hour. PYAPNS will return a list of 2-element lists\nwith the date and the token:\n\n    feedbacks = client.feedback 'cf'\n\n### Asynchronous Calls\n\nPYAPNS::Client will, by default, perform no funny stuff and operate entirely\nwithin the calling thread. This means that certain applications may hang when,\nsay, sending a notification, if only for a fraction of a second. Obviously \nnot a desirable trait, all `provision`, `feedback` and `notify`\nmethods also take a block, which indicates to the method you want to call\nPYAPNS asynchronously, and it will be done so handily in another thread, calling\nback your block with a single argument when finished. Note that `notify` and `provision`\nreturn absolutely nothing (nil, for you rub--wait you are ruby developers!).\nIt is probably wise to always use this form of operation so your calling thread\nis never blocked (especially important in UI-driven apps and asynchronous servers)\nJust pass a block to provision/notify/feedback like so:\n\n    PYAPNS::Client.instance.feedback do |feedbacks|\n      feedbacks.each { |f| trim_token f }\n    end\n\n### PYAPNS::ClientConfiguration\nA middleware class to make `PYAPNS::Client` easy to use in web contexts\n\nAutomates configuration of the client in Rack environments\nusing a simple confiuration middleware. To use `PYAPNS::Client` in\nRack environments with the least code possible `use PYAPNS::ClientConfiguration`\n(no, really, in some cases, that's all you need!) middleware with an optional\nhash specifying the client variables. Options are as follows:\n\n     use PYAPNS::ClientConfiguration(\n          :host =\u003e 'http://localhost/' \n          :port =\u003e 7077,\n          :initial =\u003e [{\n              :app_id =\u003e 'myapp',\n              :cert =\u003e '/home/myuser/apps/myapp/cert.pem',\n              :env =\u003e 'sandbox',\n              :timeout =\u003e 15\n     }])\n\nWhere the configuration variables are defined:\n\n    :host     String      the host where the server can be found\n    :port     Number      the port to which the client should connect\n    :initial  Array       OPTIONAL - an array of INITIAL hashes\n\n    INITIAL HASHES:\n\n    :app_id   String      the id used to send messages with this certification\n                          can be a totally arbitrary value\n    :cert     String      a path to the certification or the certification file\n                          as a string\n    :env      String      the environment to connect to apple with, always\n                          either 'sandbox' or 'production'\n    :timoeut  Number      The timeout for the server to use when connecting\n                          to the apple servers\n\n### PYAPNS::Notification\nAn APNS Notification\n\nYou can construct notification objects ahead of time by using this class.\nHowever unnecessary, it allows you to programmatically generate a Notification\nlike so: \n\n    note = PYAPNS::Notification.new 'alert text', 9, 'flynn.caf', {:extra =\u003e 'guid'}\n\n    -- or --\n    note = PYAPNS::Notification.new 'alert text'\n\nThese can be passed to `PYAPNS::Client#notify` the same as hashes\n\n","funding_links":[],"categories":["Python","etc"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamuraisam%2Fpyapns","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsamuraisam%2Fpyapns","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamuraisam%2Fpyapns/lists"}