-
-
Notifications
You must be signed in to change notification settings - Fork 797
/
fetchmail.py
executable file
·112 lines (97 loc) · 3.77 KB
/
fetchmail.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#!/usr/bin/env python3
import time
import os
from pathlib import Path
from pwd import getpwnam
import tempfile
import shlex
import subprocess
import requests
from socrate import system
import sys
import traceback
FETCHMAIL = """
fetchmail -N \
--idfile /data/fetchids --uidl \
--pidfile /dev/shm/fetchmail.pid \
--sslcertck --sslcertpath /etc/ssl/certs \
-f {}
"""
RC_LINE = """
poll "{host}" proto {protocol} port {port}
user "{username}" password "{password}"
is "{user_email}"
smtphost "{smtphost}"
{folders}
{options}
{lmtp}
"""
def escape_rc_string(arg):
return "".join("\\x%2x" % ord(char) for char in arg)
def fetchmail(fetchmailrc):
with tempfile.NamedTemporaryFile() as handler:
handler.write(fetchmailrc.encode("utf8"))
handler.flush()
command = FETCHMAIL.format(shlex.quote(handler.name))
output = subprocess.check_output(command, shell=True)
return output
def run(debug):
try:
fetches = requests.get(f"http://{os.environ['ADMIN_ADDRESS']}:8080/internal/fetch").json()
for fetch in fetches:
fetchmailrc = ""
options = "options antispam 501, 504, 550, 553, 554"
options += " ssl" if fetch["tls"] else ""
options += " keep" if fetch["keep"] else " fetchall"
folders = "folders %s" % ((','.join('"' + item + '"' for item in fetch['folders'])) if fetch['folders'] else '"INBOX"')
fetchmailrc += RC_LINE.format(
user_email=escape_rc_string(fetch["user_email"]),
protocol=fetch["protocol"],
host=escape_rc_string(fetch["host"]),
port=fetch["port"],
smtphost=f'{os.environ["FRONT_ADDRESS"]}' if fetch['scan'] else f'{os.environ["FRONT_ADDRESS"]}/2525',
username=escape_rc_string(fetch["username"]),
password=escape_rc_string(fetch["password"]),
options=options,
folders='' if fetch['protocol'] == 'pop3' else folders,
lmtp='' if fetch['scan'] else 'lmtp',
)
if debug:
print(fetchmailrc)
try:
print(fetchmail(fetchmailrc))
error_message = ""
except subprocess.CalledProcessError as error:
error_message = error.output.decode("utf8")
# No mail is not an error
if not error_message.startswith("fetchmail: No mail"):
print(error_message)
user_info = "for %s at %s" % (fetch["user_email"], fetch["host"])
# Number of messages seen is not a error as well
if ("messages" in error_message and
"(seen " in error_message and
user_info in error_message):
print(error_message)
finally:
requests.post("http://{}:8080/internal/fetch/{}".format(os.environ['ADMIN_ADDRESS'],fetch['id']),
json=error_message.split('\n')[0]
)
except Exception:
traceback.print_exc()
if __name__ == "__main__":
id_fetchmail = getpwnam('fetchmail')
Path('/data/fetchids').touch()
os.chown("/data/fetchids", id_fetchmail.pw_uid, id_fetchmail.pw_gid)
os.chown("/data/", id_fetchmail.pw_uid, id_fetchmail.pw_gid)
os.chmod("/data/fetchids", 0o700)
system.drop_privs_to('fetchmail')
config = system.set_env()
while True:
delay = int(os.environ.get('FETCHMAIL_DELAY', 60))
print("Sleeping for {} seconds".format(delay))
time.sleep(delay)
if not config.get('FETCHMAIL_ENABLED', True):
print("Fetchmail disabled, skipping...")
continue
run(config.get('DEBUG', False))
sys.stdout.flush()