Add Mastomail into version control
[mastomail.git] / mastomail.py
1 # mastomail.py
2 #
3 # Mastomail is a Python script that fetches replies from your Mastodon
4 # account and emails them to you. Each email includes the reply, the
5 # time it was posted, a URL to view the reply on Mastodon, and the
6 # toot being replied to.
7 #
8 # Uncomment and run register_app() and authenticate_user() on your
9 # first run, then comment them out for subsequent runs.
10 #
11 # Copyright (C) 2024 Jason Self <j@jxself.org>
12 #
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
17 #
18 # This program is distributed in the hope that it will be useful, but
19 # WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 # General Public License for more details.
22 #
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <https://www.gnu.org/licenses/>.
25
26 from mastodon import Mastodon
27 import smtplib
28 from email.mime.text import MIMEText
29 from html.parser import HTMLParser
30 from email.utils import formatdate
31
32 # Helper class to strip HTML tags except URLs
33 class MLStripper(HTMLParser):
34     def __init__(self):
35         super().__init__()
36         self.reset()
37         self.strict = False
38         self.convert_charrefs = True
39         self.text = []
40
41     def handle_starttag(self, tag, attrs):
42         if tag == 'a':
43             href = [v for k, v in attrs if k == 'href']
44             if href:
45                 self.text.append(href[0])  # Append the URL
46
47     def handle_data(self, d):
48         self.text.append(d)
49
50     def get_data(self):
51         return ''.join(self.text)
52
53 # Function to strip HTML tags but keep URLs
54 def strip_tags(html):
55     s = MLStripper()
56     s.feed(html)
57     return s.get_data()
58
59 # Register your application with Mastodon
60 def register_app():
61     Mastodon.create_app(
62          'pytooterapp',
63          api_base_url = 'https://mastodon.social',
64          to_file = 'pytooter_clientcred.secret'
65     )
66
67 # Authenticate your user account
68 def authenticate_user():
69     mastodon = Mastodon(
70         client_id='pytooter_clientcred.secret',
71         api_base_url='https://mastodon.social'
72     )
73     mastodon.log_in(
74         'your_email@example.com',
75         'your_password',
76         to_file='pytooter_usercred.secret'
77     )
78
79 # Load the Mastodon instance with all credentials
80 mastodon = Mastodon(
81     client_id='pytooter_clientcred.secret',
82     access_token='pytooter_usercred.secret',
83     api_base_url='https://mastodon.social'
84 )
85
86 # Function to fetch replies
87 def fetch_replies(since_id=None):
88     notifications = mastodon.notifications(since_id=since_id, limit=50)
89     replies = [n for n in notifications if n['type'] == 'mention']
90     return replies
91
92 # Function to format email content
93 def format_email(replies, my_mastodon_base_url):
94     email_content = ""
95     for reply in replies:
96         content = strip_tags(reply['status']['content'])
97         created_at = reply['status']['created_at']
98         toot_id = reply['status']['id']
99         # Construct the URL to the toot on your account
100         reply_url = f"{my_mastodon_base_url}/web/statuses/{toot_id}"
101
102         in_reply_to_content = ""
103         if reply['status'].get('in_reply_to_id'):
104             in_reply_to_status = mastodon.status(reply['status']['in_reply_to_id'])
105             if in_reply_to_status:
106                 in_reply_to_content = strip_tags(in_reply_to_status['content'])
107
108         email_content += f"Reply: {content}\nTime: {created_at}\nURL: {reply_url}\nIn reply to: {in_reply_to_content}\n\n"
109     return email_content
110
111 # Function to send email
112 def send_email(content):
113     sender = 'your_email@example.com'
114     receiver = 'your_email@example.com'
115     msg = MIMEText(content)
116     msg['Subject'] = 'Mastodon Replies'
117     msg['From'] = sender
118     msg['To'] = receiver
119     msg['Date'] = formatdate(localtime=True)  # Add current date and time
120
121     # SMTP server setup
122     with smtplib.SMTP('mail.example.com', 587) as server:
123         server.starttls()
124         server.login(sender, 'your_password')
125         server.sendmail(sender, receiver, msg.as_string())
126
127 # Functions to save and load the last checked ID
128 def save_last_checked_id(last_id):
129     with open('last_checked_id.txt', 'w') as f:
130         f.write(str(last_id))
131
132 def load_last_checked_id():
133     try:
134         with open('last_checked_id.txt', 'r') as f:
135             return int(f.read().strip())
136     except (FileNotFoundError, ValueError):
137         return None
138
139 def main():
140     my_mastodon_base_url = 'https://mastodon.social'  # Replace with your Mastodon instance URL
141     last_checked = load_last_checked_id()
142     new_replies = fetch_replies(since_id=last_checked)
143     if new_replies:
144         email_content = format_email(new_replies, my_mastodon_base_url)
145         send_email(email_content)
146         latest_reply_id = new_replies[0]['id']
147         save_last_checked_id(latest_reply_id)
148
149 if __name__ == '__main__':
150     main()