gakomail 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gakomail-1.0.0/PKG-INFO +6 -0
- gakomail-1.0.0/gakomail.egg-info/PKG-INFO +6 -0
- gakomail-1.0.0/gakomail.egg-info/SOURCES.txt +8 -0
- gakomail-1.0.0/gakomail.egg-info/dependency_links.txt +1 -0
- gakomail-1.0.0/gakomail.egg-info/entry_points.txt +2 -0
- gakomail-1.0.0/gakomail.egg-info/requires.txt +1 -0
- gakomail-1.0.0/gakomail.egg-info/top_level.txt +1 -0
- gakomail-1.0.0/gakomail.py +186 -0
- gakomail-1.0.0/pyproject.toml +15 -0
- gakomail-1.0.0/setup.cfg +4 -0
gakomail-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
keyring
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
gakomail
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/python3
|
|
2
|
+
# sends an email over 465/SSL
|
|
3
|
+
#
|
|
4
|
+
# usage: gakomail.py [-h] [-s SMTP_SERVER] [-e SENDER_EMAIL] [-p SENDER_PASSWORD] [-r RECEIVER_EMAIL] [-sub SUBJECT] [-m MESSAGE] [-l LIST]
|
|
5
|
+
#
|
|
6
|
+
# options:
|
|
7
|
+
# -h, --help show this help message and exit
|
|
8
|
+
# -s SMTP_SERVER, --smtp_server SMTP_SERVER
|
|
9
|
+
# SMTP server
|
|
10
|
+
# -e SENDER_EMAIL, --sender_email SENDER_EMAIL
|
|
11
|
+
# Sender email
|
|
12
|
+
# -p SENDER_PASSWORD, --sender_password SENDER_PASSWORD
|
|
13
|
+
# Sender password
|
|
14
|
+
# -r RECEIVER_EMAIL, --receiver_email RECEIVER_EMAIL
|
|
15
|
+
# Receiver email
|
|
16
|
+
# -sub SUBJECT, --subject SUBJECT
|
|
17
|
+
# Email subject
|
|
18
|
+
# -m MESSAGE, --message MESSAGE
|
|
19
|
+
# Email message content
|
|
20
|
+
# -l LIST, --list LIST Adds list-id header
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
import smtplib
|
|
24
|
+
from email.mime.text import MIMEText
|
|
25
|
+
from email.mime.multipart import MIMEMultipart
|
|
26
|
+
import argparse
|
|
27
|
+
import hashlib
|
|
28
|
+
import keyring
|
|
29
|
+
import sys
|
|
30
|
+
import os
|
|
31
|
+
from datetime import datetime
|
|
32
|
+
login_keyring=keyring.get_keyring()
|
|
33
|
+
|
|
34
|
+
# default server
|
|
35
|
+
SMTP_SERVER='example.com'
|
|
36
|
+
SMTP_USER='jane@example.com'
|
|
37
|
+
DEFAULT_RECIPIENT='jane@example.com'
|
|
38
|
+
|
|
39
|
+
# Load defaults from .env file if it exists
|
|
40
|
+
def load_env_defaults():
|
|
41
|
+
env_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '.env')
|
|
42
|
+
if os.path.exists(env_path):
|
|
43
|
+
with open(env_path, 'r') as f:
|
|
44
|
+
for line in f:
|
|
45
|
+
line = line.strip()
|
|
46
|
+
if line and not line.startswith('#') and '=' in line:
|
|
47
|
+
key, value = line.split('=', 1)
|
|
48
|
+
key = key.strip()
|
|
49
|
+
value = value.strip().strip('"').strip("'")
|
|
50
|
+
if key == 'SMTP_SERVER':
|
|
51
|
+
globals()['SMTP_SERVER'] = value
|
|
52
|
+
elif key == 'SMTP_USER':
|
|
53
|
+
globals()['SMTP_USER'] = value
|
|
54
|
+
elif key == 'DEFAULT_RECIPIENT':
|
|
55
|
+
globals()['DEFAULT_RECIPIENT'] = value
|
|
56
|
+
|
|
57
|
+
load_env_defaults()
|
|
58
|
+
|
|
59
|
+
print(f"Using SMTP_SERVER={SMTP_SERVER}, SMTP_USER={SMTP_USER}, DEFAULT_RECIPIENT={DEFAULT_RECIPIENT}")
|
|
60
|
+
|
|
61
|
+
class EmailArgs:
|
|
62
|
+
def __init__(self):
|
|
63
|
+
self.sender_email = None
|
|
64
|
+
self.sender_password = None
|
|
65
|
+
self.receiver_email = ""
|
|
66
|
+
self.bcc = ""
|
|
67
|
+
self.subject = None
|
|
68
|
+
self.message = None
|
|
69
|
+
self.smtp_server = SMTP_SERVER
|
|
70
|
+
self.list = False
|
|
71
|
+
|
|
72
|
+
def send_email(args):
|
|
73
|
+
"""
|
|
74
|
+
send an email in MIME format
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
message_type = "unknown message_type"
|
|
78
|
+
|
|
79
|
+
# Add body to the email
|
|
80
|
+
if args.message.startswith("From: ") \
|
|
81
|
+
or args.message.startswith("Content-Type: multipart/alternative")\
|
|
82
|
+
:
|
|
83
|
+
raw_email_to_be_sent = args.message
|
|
84
|
+
message_type = "raw"
|
|
85
|
+
else:
|
|
86
|
+
message_type = "MIMEMultipart"
|
|
87
|
+
|
|
88
|
+
# we construct a message
|
|
89
|
+
# Create a multipart message and set headers
|
|
90
|
+
email = MIMEMultipart()
|
|
91
|
+
email["From"] = args.sender_email
|
|
92
|
+
email["To"] = args.receiver_email
|
|
93
|
+
email["Subject"] = args.subject
|
|
94
|
+
|
|
95
|
+
# for deltachat, list-id works
|
|
96
|
+
# for thunderbird list-id does not work see https://bugzilla.mozilla.org/show_bug.cgi?id=1930358, one option is to use "References" or "In-Reply-To" or "Chat-Group-Id"
|
|
97
|
+
if args.list == True or args.list == "True":
|
|
98
|
+
email["List-id"] = args.subject+ " <"+hashlib.sha256((args.sender_email+args.receiver_email+args.subject).encode()).hexdigest()+">"
|
|
99
|
+
if isinstance(args.list, str) and args.list != "True" and args.list != "False" :
|
|
100
|
+
email["List-id"] = args.list + " <" + hashlib.sha256(args.list.encode()).hexdigest() + ">"
|
|
101
|
+
|
|
102
|
+
if args.message.startswith("<html>"):
|
|
103
|
+
content_type = "html"
|
|
104
|
+
email.attach(MIMEText(args.message, content_type))
|
|
105
|
+
raw_email_to_be_sent = email.as_string()
|
|
106
|
+
elif args.message.startswith("BEGIN:VCALENDAR"):
|
|
107
|
+
content_type = "calendar"
|
|
108
|
+
# KTH SpamAssassin hates invitations with empty message, so we add one
|
|
109
|
+
email.attach(MIMEText("please see the calendar invitation attached", "plain"))
|
|
110
|
+
email.attach(MIMEText(args.message, content_type))
|
|
111
|
+
raw_email_to_be_sent = email.as_string()
|
|
112
|
+
else:
|
|
113
|
+
# default, plain text
|
|
114
|
+
email.attach(MIMEText(args.message, "plain"))
|
|
115
|
+
raw_email_to_be_sent = \
|
|
116
|
+
f"""From: {args.sender_email}
|
|
117
|
+
To: {args.receiver_email}
|
|
118
|
+
Subject: {args.subject}
|
|
119
|
+
|
|
120
|
+
{args.message}
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
# Create SMTP session for sending the email
|
|
125
|
+
with smtplib.SMTP_SSL(args.smtp_server, 465) as server:
|
|
126
|
+
server.login(args.sender_email, args.sender_password)
|
|
127
|
+
for r in args.receiver_email.split(",") + args.bcc.split(","):
|
|
128
|
+
r = r.strip()
|
|
129
|
+
if len(r)==0: continue
|
|
130
|
+
try:
|
|
131
|
+
# print(r)
|
|
132
|
+
server.sendmail(args.sender_email, r, raw_email_to_be_sent)
|
|
133
|
+
print("gakomail.py",message_type,"sent to ",r)
|
|
134
|
+
try:
|
|
135
|
+
log_file_path = os.path.expanduser("~/.cache/gakomail.log")
|
|
136
|
+
os.makedirs(os.path.dirname(log_file_path), exist_ok=True)
|
|
137
|
+
with open(log_file_path, "a") as log_file:
|
|
138
|
+
log_file.write(f"{datetime.now().isoformat()} - To: {r}, Subject: {args.subject}\n")
|
|
139
|
+
except Exception as log_e:
|
|
140
|
+
print(f"Failed to write to log file: {log_e}", file=sys.stderr)
|
|
141
|
+
|
|
142
|
+
except Exception as e:
|
|
143
|
+
print("cannot send to ",r, file=sys.stderr)
|
|
144
|
+
raise e
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
#def send_email(smtp_server, sender_email, sender_password, receiver_email, subject, message):
|
|
148
|
+
## Create a multipart message and set headers
|
|
149
|
+
#email = MIMEMultipart()
|
|
150
|
+
#email["From"] = sender_email
|
|
151
|
+
#email["To"] = receiver_email
|
|
152
|
+
#email["Subject"] = subject
|
|
153
|
+
|
|
154
|
+
## Add body to the email
|
|
155
|
+
#email.attach(MIMEText(message, "plain"))
|
|
156
|
+
|
|
157
|
+
## Create SMTP session for sending the email
|
|
158
|
+
#with smtplib.SMTP(smtp_server, 465) as server:
|
|
159
|
+
#server.starttls()
|
|
160
|
+
#server.login(sender_email, sender_password)
|
|
161
|
+
#server.sendmail(sender_email, receiver_email, email.as_string())
|
|
162
|
+
|
|
163
|
+
def parse_and_send_email():
|
|
164
|
+
# Create an ArgumentParser object
|
|
165
|
+
parser = argparse.ArgumentParser()
|
|
166
|
+
# Add arguments to the parser with default values
|
|
167
|
+
parser.add_argument('-s', '--smtp_server', default=SMTP_SERVER, help='SMTP server')
|
|
168
|
+
parser.add_argument('-e', '--sender_email', default=SMTP_USER, help='Sender email')
|
|
169
|
+
parser.add_argument('-p', '--sender_password', default=login_keyring.get_password('login2', SMTP_USER), help='Sender password')
|
|
170
|
+
|
|
171
|
+
# recipients
|
|
172
|
+
parser.add_argument('-r', '--receiver_email', default=DEFAULT_RECIPIENT, help='Receiver email')
|
|
173
|
+
parser.add_argument('-b', '--bcc', default='', help='BCC email')
|
|
174
|
+
|
|
175
|
+
parser.add_argument('-sub', '--subject', default='Hello from gakomail.py!', help='Email subject')
|
|
176
|
+
parser.add_argument('-m', '--message', default='This is a test email sent using Python.', help='Email message content')
|
|
177
|
+
parser.add_argument('-l', '--list', default=True, help='Adds list-id header')
|
|
178
|
+
|
|
179
|
+
# Parse the arguments
|
|
180
|
+
args = parser.parse_args()
|
|
181
|
+
|
|
182
|
+
# Send the email
|
|
183
|
+
send_email(args)
|
|
184
|
+
|
|
185
|
+
if __name__ == '__main__':
|
|
186
|
+
parse_and_send_email()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "gakomail"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "A Python script to send emails over SMTP SSL"
|
|
9
|
+
requires-python = ">=3.6"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"keyring",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[project.scripts]
|
|
15
|
+
gakomail = "gakomail:parse_and_send_email"
|
gakomail-1.0.0/setup.cfg
ADDED