diff --git a/README.md b/README.md index 901c2f4..51b5eb0 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ up: bool = listmonk.is_healthy() # Read data about your lists lists: list[] = listmonk.lists() -list: MailingList = listmonk.list_by_id(list_id=7) +the_list: MailingList = listmonk.list_by_id(list_id=7) # Various ways to access existing subscribers subscribers: list[] = listmonk.subscribers(list_id=9) @@ -58,7 +58,10 @@ new_subscriber = listmonk.create_subscriber( # Change the email, custom rating, and add to lists 4 & 6, remove from 5. subscriber.email = 'newemail@some.domain' subscriber.attribs['rating'] = 7 -updated_subscriber = listmonk.update_subscriber(subscriber, {4, 6}, {5}) +subscriber = listmonk.update_subscriber(subscriber, {4, 6}, {5}) + +# Confirm single-opt-ins via the API (e.g. for when you manage that on your platform) +listmonk.confirm_optin(subscriber.uuid, the_list.uuid) # Disable then re-enable a subscriber subscriber = listmonk.disable_subscriber(subscriber) diff --git a/example_client/client.py b/example_client/client.py index b0b1874..a3f442c 100644 --- a/example_client/client.py +++ b/example_client/client.py @@ -26,8 +26,8 @@ for lst in lists: print(f'{lst.name} list: {lst}') -lst = listmonk.list_by_id(6) -print(f'List by ID: {lst}') +the_list = listmonk.list_by_id(test_list_id) +print(f'List by ID: {the_list}') print() subscribers = listmonk.subscribers(list_id=test_list_id) @@ -68,9 +68,13 @@ subscriber.attribs['rating'] = 7 # TODO: Choose list IDs from your instance (can be seen in the UI or from the listing above) -updated_subscriber = listmonk.update_subscriber(subscriber, {4, 6}, {5}) +to_add = {the_list.id} # Add all the lists here: {1, 7, 11} +remove_from = set() # Same as above +updated_subscriber = listmonk.update_subscriber(subscriber, to_add, remove_from) print(f'Updated subscriber: {updated_subscriber}') +print(f'Subscriber confirmed?: {listmonk.confirm_optin(subscriber.uuid, the_list.uuid)}') + updated_subscriber.attribs['subscription_note'] = \ "They asked to be unsubscribed so we disabled their account, but no block-listing yet." diff --git a/listmonk/__init__.py b/listmonk/__init__.py index 0734ea6..b151dcd 100644 --- a/listmonk/__init__.py +++ b/listmonk/__init__.py @@ -1,5 +1,6 @@ from listmonk import impl from listmonk import models # noqa: F401, E402 +from listmonk.impl import confirm_optin # noqa: F401, E402 from listmonk.impl import create_subscriber, delete_subscriber, update_subscriber # noqa: F401, E402 from listmonk.impl import disable_subscriber, enable_subscriber, block_subscriber # noqa: F401, E402 from listmonk.impl import is_healthy # noqa: F401, E402 @@ -22,5 +23,6 @@ create_subscriber, delete_subscriber, update_subscriber, disable_subscriber, enable_subscriber, block_subscriber, send_transactional_email, + confirm_optin, is_healthy, ] diff --git a/listmonk/impl/__init__.py b/listmonk/impl/__init__.py index 8019bc0..90a4490 100644 --- a/listmonk/impl/__init__.py +++ b/listmonk/impl/__init__.py @@ -291,6 +291,47 @@ def delete_subscriber(email: Optional[str] = None, overriding_subscriber_id: Opt # endregion + +# region def confirm_optin(subscriber_uuid: str, list_uuid: str) -> bool + +def confirm_optin(subscriber_uuid: str, list_uuid: str) -> bool: + global core_headers + validate_state(url=True, user=True) + if not subscriber_uuid: + raise ValueError("subscriber_uuid is required") + if not list_uuid: + raise ValueError("list_uuid is required") + + # + # If there is a better endpoint / API for this, please let me know. + # We're reduced to basically submitting the form via web scraping. + # + payload = { + 'l': list_uuid, + 'confirm': 'true', + + } + url = f"{url_base}{urls.opt_in.format(subscriber_uuid=subscriber_uuid)}" + resp = httpx.post(url, data=payload, follow_redirects=True) + resp.raise_for_status() + + success_phrases = { + # New conformation was created now. + 'Subscribed successfully.', + 'Confirmed', + + # They were already confirmed somehow previously. + 'no subscriptions to confirm', + 'No subscriptions' + } + + text = resp.text or '' + return any(p in text for p in success_phrases) + + +# endregion + + # region def update_subscriber(subscriber: models.Subscriber, add_to_lists: set[int], remove_from_lists: set[int]) def update_subscriber(subscriber: models.Subscriber, add_to_lists: set[int] = None, remove_from_lists: set[int] = None, diff --git a/listmonk/urls.py b/listmonk/urls.py index 64c8b18..bf92e1a 100644 --- a/listmonk/urls.py +++ b/listmonk/urls.py @@ -3,4 +3,5 @@ lst = '/api/lists/{list_id}' subscriber = '/api/subscribers/{subscriber_id}' subscribers = '/api/subscribers' +opt_in = '/subscription/optin/{subscriber_uuid}' send_tx = '/api/tx'