diff --git a/scripts/other/createemail/config-template.py b/scripts/other/createemail/config-template.py
new file mode 100644
index 0000000..30dbd10
--- /dev/null
+++ b/scripts/other/createemail/config-template.py
@@ -0,0 +1,18 @@
+"""
+examples for
+MYTOKEN="3fe723423dsd459266cec5e9ce81420c4fc2771",
+MYURL "http://paperless:8000"
+SEARCHPATH="?tags__id__all=2&custom_field_query=%5B%22OR%22,%5B%5B2,%22exists%22,%22false%22%5D%5D%5D&query=created:%5B-3%20month%20to%20now%5D,added:%5B-1%20week%20to%20now%5D&sort=added&reverse=1&page=1",
+"""
+settings = dict(
+ MYTOKEN="3fe723423dsd459266cec5e9ce81420c4fc2771",
+ MYURL="http://paperless.example.com:8000",
+ SEARCHPATH="?tags__id__all=2&custom_field_query=%5B%22OR%22,%5B%5B2,%22exists%22,%22false%22%5D%5D%5D&query=created:%5B-3%20month%20to%20now%5D,added:%5B-1%20week%20to%20now%5D&sort=added&reverse=1&page=1",
+ TO=["joe.sixpack@example.com"],
+ FROM="joe.sixpack@example.com+paperless@gmail.com",
+ SUBJECT="Paperless files in need of attendance.",
+ SMTP_HOST="localhost",
+ SMTP_PORT=25,
+ SMTP_USER="USER",
+ SMTP_PASS=""
+)
\ No newline at end of file
diff --git a/scripts/other/createemail/main.py b/scripts/other/createemail/main.py
new file mode 100644
index 0000000..9f100ed
--- /dev/null
+++ b/scripts/other/createemail/main.py
@@ -0,0 +1,186 @@
+"""
+Author: Your Name
+Date: 2024-12-12
+Synopsis: This script retrieves documents, correspondents, and tags from a Paperless instance,
+ formats their information into an HTML email, and sends it via a local Postfix server.
+
+License (MIT): See the previous example.
+"""
+
+import requests
+import smtplib
+from config import settings
+from email.mime.multipart import MIMEMultipart
+from email.mime.text import MIMEText
+from datetime import datetime, date
+
+TOKEN = settings["MYTOKEN"]
+MYURL = settings["MYURL"] # e.g. "http://paperless:8000" (no /api here)
+SEARCHPATH = settings["SEARCHPATH"] # Configurable search path for documents
+TO = settings["TO"] # Can be a string or a list
+FROM = settings["FROM"]
+SUBJECT = settings["SUBJECT"]
+
+headers = {
+ "Authorization": f"Token {TOKEN}",
+ "Accept": "application/json"
+}
+
+def safe_request(url):
+ """Make a request and handle exceptions."""
+ try:
+ response = requests.get(url, headers=headers)
+ response.raise_for_status()
+ return response.json()
+ except requests.exceptions.RequestException as e:
+ print(f"Error fetching data from {url}: {e}")
+ return None
+
+def get_correspondents():
+ url = f"{MYURL}/api/correspondents/"
+ data = safe_request(url)
+ if not data:
+ return []
+ return [
+ {"id": c["id"], "correspondent": c["name"]}
+ for c in data.get("results", [])
+ if "id" in c and "name" in c
+ ]
+
+def get_tags_map():
+ url = f"{MYURL}/api/tags/"
+ data = safe_request(url)
+ if not data:
+ return {}
+ return {t["id"]: t["name"] for t in data.get("results", []) if "id" in t and "name" in t}
+
+def get_documents():
+ """Fetch documents using the configurable SEARCHPATH."""
+ url = f"{MYURL}/api/documents/{SEARCHPATH}"
+ data = safe_request(url)
+ if not data:
+ return []
+ return data.get("results", [])
+
+def get_document_details(doc_id):
+ url = f"{MYURL}/api/documents/{doc_id}/"
+ data = safe_request(url)
+ if not data:
+ return "N/A", "N/A", None
+ return (
+ data.get("original_file_name", "N/A"),
+ data.get("archived_file_name", "N/A"),
+ data.get("created_date", None),
+ )
+
+def calculate_age(created_date_str):
+ if not created_date_str:
+ return "N/A"
+ try:
+ created_date = datetime.strptime(created_date_str, "%Y-%m-%d").date()
+ today = date.today()
+ age_days = (today - created_date).days
+ return age_days
+ except ValueError:
+ return "N/A"
+
+def create_email(docs, correspondents, tag_map):
+ corr_map = {c["id"]: c["correspondent"] for c in correspondents}
+
+ # Sort documents by Age (descending)
+ sorted_docs = sorted(
+ docs,
+ key=lambda d: calculate_age(d.get("created_date")),
+ reverse=True,
+ )
+
+ lines = []
+ for doc in sorted_docs:
+ try:
+ doc_id = doc.get("id")
+ corr_id = doc.get("correspondent")
+ doc_tags = doc.get("tags", [])
+
+ if not doc_id:
+ continue
+
+ corr_name = corr_map.get(corr_id, "No Correspondent")
+
+ original_file_name, archived_file_name, created_date_str = get_document_details(doc_id)
+ age = calculate_age(created_date_str)
+
+ # Format age
+ if isinstance(age, int) and age > 31:
+ age_str = f"{age}"
+ else:
+ age_str = str(age)
+
+ # Map tag IDs to names
+ tag_names = [tag_map.get(tid, f"Tag-{tid}") for tid in doc_tags]
+ tags_str = ", ".join(tag_names) if tag_names else "None"
+
+ # Make the correspondent's name the link to the file
+ detail_url = f"{MYURL}/documents/{doc_id}/"
+ corr_link = f"{corr_name}"
+
+ # Add blank line before each bullet
+ lines.append(
+ f"
Here are your documents:
+Your trusted PaperlessNGX Runner
+ + +""" + + subject_with_count = f"{SUBJECT} ({len(docs)})" + + msg = MIMEMultipart("alternative") + msg["Subject"] = subject_with_count + msg["From"] = FROM + if isinstance(TO, list): + msg["To"] = ", ".join(TO) + else: + msg["To"] = TO + + part = MIMEText(html_body, "html") + msg.attach(part) + + return msg + +def send_email(msg): + try: + with smtplib.SMTP("localhost", 25) as server: + server.send_message(msg) + except Exception as e: + print(f"Error sending email: {e}") + +if __name__ == "__main__": + try: + correspondents = get_correspondents() + tag_map = get_tags_map() + docs = get_documents() + email_msg = create_email(docs, correspondents, tag_map) + send_email(email_msg) + print("Email sent.") + except Exception as e: + print(f"Error during execution: {e}")