{ "info": { "author": "Mikko Ohtamaa", "author_email": "mikko@opensourcehacker.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Framework :: Pyramid", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Internet :: WWW/HTTP :: WSGI :: Application" ], "description": "This is a newsletter addon for `Websauna framework `_. It is intended for automatic newsletter generation from the site content.\n\n.. |ci| image:: https://img.shields.io/travis/websauna/websauna.newsletter/master.svg?style=flat-square\n :target: https://travis-ci.org/websauna/websauna.newsletter/\n\n.. |latest| image:: https://img.shields.io/pypi/v/websauna.newsletter.svg\n :target: https://pypi.python.org/pypi/websauna.newsletter/\n :alt: Latest Version\n\n.. |license| image:: https://img.shields.io/pypi/l/websauna.newsletter.svg\n :target: https://pypi.python.org/pypi/websauna.newsletter/\n :alt: License\n\n.. |versions| image:: https://img.shields.io/pypi/pyversions/websauna.newsletter.svg\n :target: https://pypi.python.org/pypi/websauna.newsletter/\n :alt: Supported Python versions\n\n+-----------+-----------+\n| |versions|| |latest| |\n+-----------+-----------+\n| |ci| | |license| |\n+-----------+-----------+\n\n.. image:: https://websauna.org/theme/images/logo-768.png\n\n.. contents:: :local:\n\nFeatures\n========\n\n* Automatic newsletter generation from site content\n\n* Admin interface for newsletter preview and send\n\n* Import all site users as newsletter subscribers\n\n* Outbound email through `Mailgun `_\n\n* Unsubscribe management through Mailgun\n\n* Redis based newsletter state management (when the last letter went out, etc.)\n\n* Websauna's Celery based task subsystem is used to run long running operations asynchronously\n\nInstallation\n============\n\nTo run this package you need Python 3.4+, PostgresSQL and Redis.\n\nYou need to provide your own site-specific INewsletter implementation that populates the news letter content.\n\nInstalling Python package\n-------------------------\n\nInstall this package using ``pip``.\n\nSetup newsletter renderer\n-------------------------\n\nYou need to register a site specific newsletter that is responsible for rendering your newsletter HTML payload. Do this in your ``Initializer.configure_views``. Example:\n\n.. code-block:: python\n\n # Configure newsletter renderer\n from mysite.views.newsletter import NewsletterRenderer\n from websauna.newsletter.interfaces import INewsletterGenerator\n registry = self.config.registry\n registry.registerAdapter(factory=NewsletterRenderer, required=(IRequest,), provided=INewsletterGenerator)\n\nFor more information see ``demo.py``.\n\nUnsubscription link\n-------------------\n\nIn your renderer HTML code you can use Mailgun unsubscription management:\n\n.. code-block:: html\n\n

\n {# For Mailgun #}\n Unsubscribe from TokenMarket newsletter.\n

\n\nSetting up the secrets\n----------------------\n\nAdd Mailgun API keys and such in ``myapp/conf/development-secrets.ini``.\n\nExample:\n\n.. code-block:: ini\n\n [mailgun]\n # Get from Mailgun\n api_key = x\n\n # What is the mailing list we use in the test suite\n mailing_list = unit-testing@mailgun.websauna.org\n\n # Outbound domain used for the newslettering\n domain = mailgun.websauna.org\n\n # From: email we use to send the newsletter\n from = MyApp Newsletter \n\nCreate Mailgun mailing list object\n----------------------------------\n\nEasiest to do this through ``ws-shell`` using production configuraition::\n\n ws-shell tokenmarket/conf/production.ini\n\nThen using ``%cpaste`` notebook shell command::\n\n from websauna.system.core.utils import get_secrets\n from websauna.newsletter.mailgun import Mailgun\n secrets = get_secrets(request.registry)\n list_address = secrets[\"mailgun.mailing_list\"]\n mailgun = Mailgun(request.registry)\n mailgun.create_list(list_address, \"MyApp newsletter\")\n\nYou get a reply::\n\n {'list': {'access_level': 'readonly',\n 'address': 'newsletter@example.com',\n 'created_at': 'Wed, 25 Jan 2017 17:08:56 -0000',\n 'description': 'TokenMarket newsletter',\n 'members_count': 0,\n 'name': ''},\n 'message': 'Mailing list has been created'}\n\nIntegration subscription for on your site\n-----------------------------------------\n\nA boostrap based mini subscription form is provided with the packag. It is ideal e.g. to place in the site footer.\n\nSimply in your template do::\n\n

Follow

\n {% include \"newsletter/subscription_form.html\" %}\n\n\nFor more information run the demo and view ``demotemplates/site/footer.html``.\n\nUsage\n=====\n\nSending and preview\n-------------------\n\nVisit *Newsletter* tab in the admin interface to preview and send out newsletters.\n\nResetting the news collection date\n----------------------------------\n\nYou can manually set the newsletter state, when the last newsletter was sent, from shell:\n\n.. code-block:: python\n\n import datetime\n from websauna.newsletter.state import NewsletterState\n\n state = NewsletterState(request)\n state.set_last_send_timestamp(datetime.datetime(2016, 12, 24).replace(tzinfo=datetime.timezone.utc))\n\nState is managed in Redis.\n\nExporting subscribers\n---------------------\n\nIn console:\n\n.. code-block:: python\n\n from websauna.system.core.utils import get_secrets\n from websauna.newsletter.mailgun import Mailgun\n secrets = get_secrets(request.registry)\n list_address = secrets[\"mailgun.mailing_list\"]\n mailgun = Mailgun(request.registry)\n print(mailgun.list_members(list_address)) # TODO: pagination\n\nImporting email subscribers\n---------------------------\n\nNote that importing website users is supported in the admin interface.\n\nExample:\n\n.. code-block:: python\n\n subscribers = \"\"\"\n mikko@example.com\n pete@example.com\n \"\"\"\n\n from websauna.system.core.utils import get_secrets\n from websauna.newsletter.mailgun import Mailgun\n from websauna.newsletter.views import subscribe_email\n\n secrets = get_secrets(request.registry)\n list_address = secrets[\"mailgun.mailing_list\"]\n mailgun = Mailgun(request.registry)\n\n for s in subscribers.split():\n s = s.strip()\n if s:\n subscribe_email(request, s)\n\nLocal development mode\n======================\n\nYou can development this addon locally.\n\nActivate the virtual environment of your Websauna application.\n\nThen:\n\n.. code-block:: console\n\n cd newsletter # This is the folder with setup.py file\n pip install -e .\n psql create newsletter_dev\n ws-sync-db ws://websauna/newsletter/conf/development.ini\n pserve ws://websauna/newsletter/conf/development.ini --reload\n\nRunning the test suite\n======================\n\nFirst create test database::\n\n # Create database used for unit testing\n psql create newsletter_test\n\nInstall test and dev dependencies (run in the folder with ``setup.py``)::\n\n pip install -e \".[dev,test]\"\n\nRun test suite using py.test running::\n\n py.test\n\nManually testing with Celery\n----------------------------\n\nMake sure Celery is not eager in ``development.ini``::\n\n websauna.celery_config =\n {\n \"broker_url\": \"redis://localhost:6379/15\",\n \"task_always_eager\": False,\n }\n\nStart demo (Terminal 1)::\n\n pserve ws://websauna/newsletter/conf/development.ini\n\nStart Celery (Terminal 2)::\n\n ws-celery ws://websauna/newsletter/conf/development.ini -- worker\n\n\n\n\nTODO\n====\n\n * Double confirmation to the mailing list subscription\n\nMore information\n================\n\nPlease see https://websauna.org/\n\nChangelog for Websauna Newsletter\n=================================\n\n1.0a3 (2018-10-03)\n------------------\n\n- After subscription, redirect user back to original url.\n\n- Support for Python 3.7.\n\n\n1.0a2 (2018-04-22)\n------------------\n\n- Fix missing 'namespace_packages'.\n\n\n1.0a1 (2018-03-06)\n------------------\n\n- Initial Release\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://websauna.org", "keywords": "web websauna pyramid", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "websauna.newsletter", "package_url": "https://pypi.org/project/websauna.newsletter/", "platform": "", "project_url": "https://pypi.org/project/websauna.newsletter/", "project_urls": { "Homepage": "https://websauna.org" }, "release_url": "https://pypi.org/project/websauna.newsletter/1.0a3/", "requires_dist": [ "websauna[celery]", "websauna.magiclogin", "websauna[test,dev]; extra == 'dev'", "codecov; extra == 'test'", "flake8; extra == 'test'", "pytest (>=3.0); extra == 'test'", "pytest-runner; extra == 'test'", "coverage; extra == 'test'", "flaky; extra == 'test'", "isort; extra == 'test'", "pytest-cov; extra == 'test'", "pytest-runner; extra == 'test'", "pytest-splinter; extra == 'test'", "pytest-timeout; extra == 'test'", "webtest; extra == 'test'" ], "requires_python": ">=3.5.2", "summary": "Newsletter add on for Websauna", "version": "1.0a3" }, "last_serial": 4338156, "releases": { "1.0a1": [ { "comment_text": "", "digests": { "md5": "3bb6becea05ef9c111617f912e3aae1e", "sha256": "8bb9a56fa19b4c4d7d5e532a709616552484605a91f4e9d4c6ee3704f467913d" }, "downloads": -1, "filename": "websauna.newsletter-1.0a1-py3-none-any.whl", "has_sig": false, "md5_digest": "3bb6becea05ef9c111617f912e3aae1e", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 38136, "upload_time": "2018-03-06T22:33:35", "url": "https://files.pythonhosted.org/packages/03/63/c22c06adacdda9d1ed7416fd8d7e83266c3833151f6eb71205722320d53e/websauna.newsletter-1.0a1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e08acb823b3cea4366219201eeb9adb7", "sha256": "6d8f6dfbf1fa9ce3b0934ce8783928594528552f16cac3ca180ec8406fd823ad" }, "downloads": -1, "filename": "websauna.newsletter-1.0a1.tar.gz", "has_sig": false, "md5_digest": "e08acb823b3cea4366219201eeb9adb7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 32848, "upload_time": "2018-03-06T22:33:37", "url": "https://files.pythonhosted.org/packages/ee/67/9d41c14771448e6919ffd563acc4d6ff1be1d8788c44cb8051a51b286743/websauna.newsletter-1.0a1.tar.gz" } ], "1.0a2": [ { "comment_text": "", "digests": { "md5": "ec428c3835ff9811705590f3822f0a1a", "sha256": "24db9391cfed36b773a7344c51a68960713554837b378ffd63fa2e324db759e5" }, "downloads": -1, "filename": "websauna.newsletter-1.0a2-py3-none-any.whl", "has_sig": false, "md5_digest": "ec428c3835ff9811705590f3822f0a1a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 38670, "upload_time": "2018-04-22T19:09:33", "url": "https://files.pythonhosted.org/packages/02/0e/efaed0fb43d25328bc409087d7255d042d582219c194e34c61e0d645f2d7/websauna.newsletter-1.0a2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "2b32a27cde0decf4719162da9f2fb8a7", "sha256": "6e77e71410cbabb476002d0e083b1a37919aac6079c626da082c516cc480bcd7" }, "downloads": -1, "filename": "websauna.newsletter-1.0a2.tar.gz", "has_sig": false, "md5_digest": "2b32a27cde0decf4719162da9f2fb8a7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 33002, "upload_time": "2018-04-22T19:09:35", "url": "https://files.pythonhosted.org/packages/f2/13/ce01b7e4e2aa124648a8a57b8bb61960b40983b24da6690f3751d5e2611c/websauna.newsletter-1.0a2.tar.gz" } ], "1.0a3": [ { "comment_text": "", "digests": { "md5": "db630a393c5f48bc3c8a4c0de4f77043", "sha256": "6bb8df431bcf1301102f00b80232f1d2397861a00a119406115696741058ead6" }, "downloads": -1, "filename": "websauna.newsletter-1.0a3-py3-none-any.whl", "has_sig": false, "md5_digest": "db630a393c5f48bc3c8a4c0de4f77043", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5.2", "size": 35743, "upload_time": "2018-10-03T21:13:00", "url": "https://files.pythonhosted.org/packages/e2/df/760bbde4f76de8b9b8ab4bc1441a6830eb213eebf136fb5ea472872bdd15/websauna.newsletter-1.0a3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4261cc03780e6108a7522c88c47b4ef0", "sha256": "83f871d82506ddda66fcf46bd687ae57c233bd66dc9281482ce7963dbcad782b" }, "downloads": -1, "filename": "websauna.newsletter-1.0a3.tar.gz", "has_sig": false, "md5_digest": "4261cc03780e6108a7522c88c47b4ef0", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5.2", "size": 34942, "upload_time": "2018-10-03T21:13:02", "url": "https://files.pythonhosted.org/packages/e6/67/d4801fadfaec6ee85b8bd03c274607f2f78c09d385b4bd793cef3bd0457e/websauna.newsletter-1.0a3.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "db630a393c5f48bc3c8a4c0de4f77043", "sha256": "6bb8df431bcf1301102f00b80232f1d2397861a00a119406115696741058ead6" }, "downloads": -1, "filename": "websauna.newsletter-1.0a3-py3-none-any.whl", "has_sig": false, "md5_digest": "db630a393c5f48bc3c8a4c0de4f77043", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5.2", "size": 35743, "upload_time": "2018-10-03T21:13:00", "url": "https://files.pythonhosted.org/packages/e2/df/760bbde4f76de8b9b8ab4bc1441a6830eb213eebf136fb5ea472872bdd15/websauna.newsletter-1.0a3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4261cc03780e6108a7522c88c47b4ef0", "sha256": "83f871d82506ddda66fcf46bd687ae57c233bd66dc9281482ce7963dbcad782b" }, "downloads": -1, "filename": "websauna.newsletter-1.0a3.tar.gz", "has_sig": false, "md5_digest": "4261cc03780e6108a7522c88c47b4ef0", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5.2", "size": 34942, "upload_time": "2018-10-03T21:13:02", "url": "https://files.pythonhosted.org/packages/e6/67/d4801fadfaec6ee85b8bd03c274607f2f78c09d385b4bd793cef3bd0457e/websauna.newsletter-1.0a3.tar.gz" } ] }