Prevents exception between fetch and ack loosing the ack. In cases of transient problems, the ack will be sent on the next pass.
112 lines
3.4 KiB
Python
Executable file
112 lines
3.4 KiB
Python
Executable file
#!/bin/env/python3
|
|
import os
|
|
import email
|
|
from datetime import datetime
|
|
|
|
from imapclient import IMAPClient
|
|
from smtplib import SMTP_SSL
|
|
|
|
from dateutil.parser import parse as d_parse
|
|
from cron_descriptor import get_description
|
|
from croniter import croniter
|
|
|
|
|
|
help_text = """
|
|
A very comprehensive help text
|
|
"""
|
|
service_address = "remindme@friedersdorff.com"
|
|
|
|
def empty_reply(msg):
|
|
reply = email.message.EmailMessage()
|
|
reply["Subject"] = f"RE: {msg['Subject']}"
|
|
reply["Message-ID"] = email.utils.make_msgid()
|
|
reply["In-Reply-To"] = msg["Message-ID"]
|
|
reply["References"] = msg["Message-ID"]
|
|
reply["To"] = msg["Reply-To"] or msg["From"]
|
|
reply["From"] = service_address
|
|
return reply
|
|
|
|
|
|
def list_reminders(person, client):
|
|
persons_messages = client.fetch(
|
|
client.search(["FROM", person]), "BODY.PEEK[]"
|
|
)
|
|
reminders = []
|
|
for uid, reminder in persons_messages.items():
|
|
reminder = email.message_from_bytes(reminder[b"BODY[]"])
|
|
reminders.append(
|
|
f"({uid}) {reminder['Subject']}: {reminder.get_payload().strip()}"
|
|
)
|
|
return "\n".join(reminders)
|
|
|
|
|
|
def ack_message(uid, message, client):
|
|
print(message)
|
|
msg = email.message_from_bytes(message[b"BODY[]"])
|
|
if msg.is_multipart():
|
|
print("Deleting multipart message")
|
|
return None, True
|
|
client.delete_messages([uid])
|
|
|
|
payload = msg.get_payload().strip()
|
|
if payload.startswith("help"):
|
|
reply = empty_reply(msg)
|
|
reply.set_content(help_text)
|
|
return reply, True
|
|
|
|
reply = empty_reply(msg)
|
|
reply.set_content(list_reminders(msg["From"], client))
|
|
|
|
if payload.startswith("list"):
|
|
reply["Subject"] = (
|
|
f"List of active reminders (was: {reply['Subject']})"
|
|
)
|
|
return reply, True
|
|
else:
|
|
msg.replace_header("Subject", f"Set reminder: {reply['Subject']}")
|
|
prefix = (f"Successfully set reminder: {payload}.\n\n"
|
|
"Your reminders are:")
|
|
reply.set_content(f"{prefix}\n{reply.get_content()}")
|
|
return reply, False
|
|
|
|
if payload.startswith("repeat"):
|
|
try:
|
|
print(get_description(payload))
|
|
it = croniter(payload, datetime.now())
|
|
print(it.get_next(datetime))
|
|
except Exception as e:
|
|
print("Invalid Cron: ", e)
|
|
return None, False
|
|
|
|
|
|
def main():
|
|
mhost = "mail.friedersdorff.com"
|
|
user = os.environ["REMINDME_USERNAME"]
|
|
passwd = os.environ["REMINDME_PASS"]
|
|
with IMAPClient(host=mhost) as iclient, SMTP_SSL(mhost) as sclient:
|
|
print("Inside context manager")
|
|
iclient.login(user, passwd)
|
|
sclient.login(user, passwd)
|
|
iclient.select_folder("INBOX")
|
|
|
|
unseen_msgs = iclient.fetch(iclient.search(["UNSEEN"]), "BODY.PEEK[]")
|
|
for uid, message in unseen_msgs.items():
|
|
print(uid)
|
|
reply, delete = ack_message(uid, message, iclient)
|
|
|
|
try:
|
|
if reply:
|
|
print("Replying to message")
|
|
print("reply")
|
|
sclient.send_message(reply)
|
|
if delete:
|
|
print("Deleting message")
|
|
#iclient.delete_messages([uid])
|
|
else:
|
|
print("Setting msg as seen")
|
|
#iclient.set_flags([uid], [r"\SEEN"])
|
|
except Exception as e:
|
|
print("An error occured", e)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|