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
|
#!/usr/bin/env python3
#
# Send the memo in standard input to a memo server.
#
# This work is in the public domain. See the NOCOPYRIGHT file in this
# repository for details.
#
from ememo_common import parse_header_line, parse_address
import sys
import socket
import certifi
import ssl
from time import time
PORT = 6935
# This is currently hardcoded, we might use SRV records in the future.
# That would put some dependency on DNS but that shouldn't be an issue.
client_cert = "fullchain.pem"
client_key = "privkey.pem"
context = ssl.create_default_context(cafile=certifi.where())
context.load_cert_chain(certfile=client_cert, keyfile=client_key)
if len(sys.argv) >= 2:
with open(sys.argv[1], "rb") as f:
d = f.read()
else:
d = sys.stdin.buffer.read()
header, data_and_beyond = d.split(b"\n\n", 1)
headers = {}
for line in header.split(b"\n"):
k, v = parse_header_line(line)
if k is Exception:
print(v.decode("utf-8"))
sys.exit(1)
headers[k] = v
headers[b"send-server-time"] = str(time()).encode("ascii")
to = headers.get(b"to", None)
cc = headers.get(b"cc", None)
bcc = headers.get(b"bcc", None)
l_to = [parse_address(a) for a in to.split(b", ")] if to else []
l_cc = [parse_address(a) for a in cc.split(b", ")] if cc else []
l_bcc = [parse_address(a) for a in bcc.split(b", ")] if bcc else []
bccs_by_server = {}
for r in l_to + l_cc:
if not r[2] in bccs_by_server:
bccs_by_server[r[2]] = []
for r in l_bcc:
if not r[2] in bccs_by_server:
bccs_by_server[r[2]] = [r]
else:
bccs_by_server[r[2]].append(r)
bcc_header_by_server = {}
for server_addr_b in bccs_by_server:
if not bccs_by_server[server_addr_b]:
bcc_header_by_server[server_addr_b] = None
else:
bcc_header_by_server[server_addr_b] = b", ".join(
[
(
b"%s <%s@%s>" % (r[0], r[1], r[2])
if r[0]
else b"%s@%s" % (r[1], r[2])
)
for r in bccs_by_server[server_addr_b]
]
)
sbs = {}
for server_addr_b in bcc_header_by_server:
server_addr = server_addr_b.decode("utf-8", "surrogateescape")
sendbuf = b""
for k, v in headers.items():
if k != b"bcc":
sendbuf += b"%s: %s\n" % (k, v)
elif k == b"bcc" and bcc_header_by_server[server_addr_b]:
sendbuf += b"bcc: %s\n" % bcc_header_by_server[server_addr_b]
sendbuf += b"\n"
sendbuf += data_and_beyond
sbs[server_addr] = sendbuf
for server_addr, sendbuf in sbs.items():
print(server_addr)
conn = context.wrap_socket(
socket.socket(socket.AF_INET, socket.SOCK_STREAM),
server_hostname=server_addr,
)
conn.connect((server_addr, PORT))
conn.send(b"MAIL %d\n" % len(sendbuf))
conn.send(sendbuf)
s = conn.recv(512)
sys.stdout.buffer.write(s)
conn.send(b"BYE\n")
while True:
s = conn.recv(512)
if s == b"":
break
sys.stdout.buffer.write(s)
conn.shutdown(socket.SHUT_RDWR)
conn.close()
|