{"result":{"depiction_url":null,"edges":{"observes":{"objects":[{"created":"2026-10-22T10:38:37Z","object_id":{"id":1816,"is_a":["text","documentation","reference","notification"],"name":"doc_notification_email_failed","title":"observe_email_failed\/2","uri":"https:\/\/zotonic.com\/id\/1816"},"seq":1},{"created":"2026-10-22T10:38:37Z","object_id":{"id":2105,"is_a":["text","documentation","reference","notification"],"name":"doc_notification_email_bounced","title":"observe_email_bounced\/2","uri":"https:\/\/zotonic.com\/id\/2105"},"seq":2},{"created":"2026-10-22T10:38:37Z","object_id":{"id":2108,"is_a":["text","documentation","reference","notification"],"name":"doc_notification_email_sent","title":"observe_email_sent\/2","uri":"https:\/\/zotonic.com\/id\/2108"},"seq":3}],"predicate":{"id":2550,"is_a":["meta","predicate"],"name":"observes","title":{"_type":"trans","tr":{"en":"Observes"}},"uri":"https:\/\/zotonic.com\/id\/observes"}},"subject":{"objects":[{"created":"2026-10-22T10:38:37Z","object_id":{"id":2555,"is_a":["categorization","keyword","keyword_information_type"],"name":"zotonic_topic_reference","title":"Reference","uri":"https:\/\/zotonic.com\/id\/2555"},"seq":1},{"created":"2026-10-22T10:38:37Z","object_id":{"id":2562,"is_a":["categorization","keyword","keyword_audience"],"name":"zotonic_topic_site_administrator","title":"Site administrator","uri":"https:\/\/zotonic.com\/id\/2562"},"seq":2},{"created":"2026-10-22T10:38:37Z","object_id":{"id":2565,"is_a":["categorization","keyword","keyword_audience"],"name":"zotonic_topic_integrator","title":"Integrator","uri":"https:\/\/zotonic.com\/id\/2565"},"seq":3},{"created":"2026-10-22T10:38:37Z","object_id":{"id":2594,"is_a":["categorization","keyword","keyword_domain"],"name":"zotonic_topic_email","title":"Email","uri":"https:\/\/zotonic.com\/id\/2594"},"seq":4},{"created":"2026-10-22T10:38:37Z","object_id":{"id":2599,"is_a":["categorization","keyword","keyword_domain"],"name":"zotonic_topic_api_and_integration","title":"API and integration","uri":"https:\/\/zotonic.com\/id\/2599"},"seq":5},{"created":"2026-10-22T10:38:37Z","object_id":{"id":2603,"is_a":["categorization","keyword","keyword_domain"],"name":"zotonic_topic_configuration","title":"Configuration","uri":"https:\/\/zotonic.com\/id\/2603"},"seq":6},{"created":"2026-10-22T10:38:37Z","object_id":{"id":2635,"is_a":["categorization","keyword","keyword_architecture"],"name":"zotonic_topic_module","title":"Module","uri":"https:\/\/zotonic.com\/id\/2635"},"seq":7},{"created":"2026-10-22T10:38:37Z","object_id":{"id":2686,"is_a":["categorization","keyword","keyword_quality"],"name":"zotonic_topic_privacy","title":"Privacy","uri":"https:\/\/zotonic.com\/id\/2686"},"seq":8}],"predicate":{"id":308,"is_a":["meta","predicate"],"name":"subject","title":{"_type":"trans","tr":{"en":"Keyword"}},"uri":"http:\/\/purl.org\/dc\/elements\/1.1\/subject"}}},"id":3110,"is_a":["text","documentation","reference","module"],"links":[{"rel":"self","target":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/3110"},{"rel":"hub","target":"https:\/\/zotonic.com\/.zotonic\/websub"}],"medium":null,"medium_url":null,"name":"doc_external_10_mod_secure_message","page_url":{"en":"https:\/\/zotonic.com\/docs\/3110\/mod_secure_message","x-default":"https:\/\/zotonic.com\/docs\/3110\/mod_secure_message"},"preview_url":null,"resource":{"version":23,"pivot_location_lat":null,"title":"mod_secure_message","is_authoritative":true,"body":"<p>Store short-lived messages on the site and email recipients a signed link\ninstead of the message body. Recipients can read, reply to and delete a\nmessage without logging in. Replies and delivery\/read events are sent to\nan external service as JSON.<\/p>\n<h2>Setup and configuration<\/h2>\n<p>Enable <code>mod_secure_message<\/code> on a database-backed site with outgoing email\nconfigured. Schema installation creates <code>secure_message<\/code> and\n<code>secure_message_event<\/code>. The supplied pages use the site&#39;s <code>base.tpl<\/code>,\n<code>email_base.tpl<\/code>, Zotonic wires and localization templates. Customize\n<code>email_secure_message.tpl<\/code> for the site&#39;s notification text.<\/p>\n<p>Senders use the <code>m_secure_message<\/code> relay API and need <code>use<\/code> permission for\n<code>mod_secure_message<\/code>. HTTP access uses Zotonic&#39;s standard model API and its\nconfigured authentication. Recipient access instead requires the complete\nsigned link. Both page dispatch rules request HTTPS:<\/p>\n<ul><li><code>secure_message_view<\/code>: <code>\/secure\/msg\/&lt;key&gt;\/&lt;signature&gt;<\/code>.<\/li><li><code>secure_message_form<\/code>: <code>\/secure\/msg<\/code>, a form for a new contact message.<\/li><\/ul>\n<p>Per-site configuration values are:<\/p>\n<table class=\"table\"><thead><tr><th>Key under <code>mod_secure_message<\/code><\/th><th>Purpose<\/th><\/tr><\/thead><tbody><tr><td><code>event_url<\/code><\/td><td>Default JSON callback URL for contact-form messages and events without a message-specific <code>reply_url<\/code>.<\/td><\/tr><tr><td><code>sign_key_secret<\/code><\/td><td>Site secret used to sign links; generated and saved on first use if empty. Changing it invalidates existing links.<\/td><\/tr><tr><td><code>log_cleanup<\/code><\/td><td>If true, hourly cleanup also deletes rows older than seven days from the site&#39;s <code>log<\/code> and <code>log_email<\/code> tables. Defaults to disabled.<\/td><\/tr><\/tbody><\/table>\n<p>Callbacks use <code>z_fetch<\/code> in the context of user 1. Configure any destination\ncredentials through Zotonic&#39;s URL-fetch authentication integration. This\nmodule does not read the legacy <code>event_oauth_key<\/code> or <code>event_oauth_secret<\/code>\nsettings and does not itself sign outgoing requests with OAuth 1.<\/p>\n<h2>Message lifetime and events<\/h2>\n<p>Messages expire seven days after insertion. Expired links stop working at\nexpiry; the hourly <code>tick_1h<\/code> observer removes expired database rows. Reading\ndoes not extend the expiry. Recipient deletion removes the row immediately;\nassociated message-event rows are deleted by the database&#39;s cascading\nforeign key.<\/p>\n<p>Reading logs the peer address and user agent, records the first-open time,\nand queues a <code>read<\/code> event. Email notifications produce <code>sent<\/code>, <code>failed<\/code> and\n<code>bounced<\/code> callbacks for known outgoing messages; <code>sender_disabled<\/code> failures\nare ignored. Replies queue a <code>reply<\/code> event, optionally followed by deletion.\nThe page shows a reply form only when the message has a <code>reply_url<\/code>.<\/p>\n<p>Callbacks are queued for delivery after one second. Failed HTTP requests\nare rescheduled after 1800 seconds. The form&#39;s success display means the\nevent was queued, not that the receiving service accepted it.<\/p>\n<h2>Storage and link access<\/h2>\n<p>The message HTML is sanitized before storage. Payloads are serialized Erlang\nterms in a database bytea column; encryption is not implemented. Possession\nof the signed link permits reading, replying and deletion until expiry.\nDeletion covers the live message and its event rows, not database backups,\nexternal callback copies or unrelated logs.<\/p>","slug":"mod_secure_message","doc_module_config":[],"is_protected":false,"visible_for":0,"tz":"UTC","language":["en"],"doc_source_hash":"41eed1e3b75b247b95c4d25f36ffec31e9c4383cbba83396ed5ea34d5467d73d","doc_module_observers":[{"name":"email_bounced","page_name":"doc_notification_email_bounced"},{"name":"email_failed","page_name":"doc_notification_email_failed"},{"name":"email_sent","page_name":"doc_notification_email_sent"},{"name":"tick_1h","page_name":"doc_notification_tick_1h"}],"is_featured":false,"content_group_id":{"id":2551,"is_a":["meta","content_group"],"name":"content_group_imported_docs","title":"Imported documentation","uri":"https:\/\/zotonic.com\/id\/content_group_imported_docs"},"external_module_id":{"id":10,"is_a":[],"name":null,"title":null,"uri":"https:\/\/zotonic.com\/id\/10"},"git_url":"https:\/\/github.com\/zotonic\/zotonic_mod_secure_message.git","category_id":{"id":320,"is_a":["meta","category"],"name":"module","title":"Modules","uri":"https:\/\/test.zotonic.com\/id\/320"},"doc_source_path":".\/src\/mod_secure_message.erl","publication_start":"2026-10-22T10:38:38Z","github_url":"https:\/\/github.com\/zotonic\/zotonic_mod_secure_message.git","pivot_location_lng":null,"doc_source_kind":"external","name":"doc_external_10_mod_secure_message","is_unfindable":false,"is_published":true,"pivot_geocode":null,"external_module_title":"Secure Message","created":"2026-10-22T10:38:37Z","uri":null,"doc_status":"current","is_dependent":false,"is_external_module":true,"publication_end":"9999-06-01T00:00:00Z","modifier_id":{"id":1,"is_a":["person"],"name":"administrator","title":"Site Administrator","uri":"https:\/\/zotonic.com\/id\/1"},"privacy":0,"doc_source_commit":"613b1e440b3dfa3c15596b16f0200bdab3ff4f21","creator_id":{"id":1,"is_a":["person"],"name":"administrator","title":"Site Administrator","uri":"https:\/\/zotonic.com\/id\/1"},"modified":"2026-10-22T10:38:38Z","title_slug":"mod_secure_message"},"uri":"https:\/\/zotonic.com\/id\/3110","uri_template":"https:\/\/zotonic.com\/id\/:id","websub":{"hub":"https:\/\/zotonic.com\/.zotonic\/websub","topic":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/3110"}},"status":"ok"}