#!/usr/bin/env python3
##
## SPDX-FileCopyrightText: © 2007-2024 Benedict Verhegghe <bverheg@gmail.com>
## SPDX-License-Identifier: GPL-3.0-or-later
##
## This file is part of pyFormex 3.5 (Thu Feb 8 19:11:13 CET 2024)
## pyFormex is a tool for generating, manipulating and transforming 3D
## geometrical models by sequences of mathematical operations.
## Home page: https://pyformex.org
## Project page: https://savannah.nongnu.org/projects/pyformex/
## Development: https://gitlab.com/bverheg/pyformex
## Distributed under the GNU General Public License version 3 or later.
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program. If not, see http://www.gnu.org/licenses/.
##
"""sendmail.py: a simple program to send an email message
"""
import os
import smtplib
import socket
import getpass
from email.message import EmailMessage
################### global data ##################################
host = socket.gethostname()
user = getpass.getuser()
mail = os.environ.get('MAIL', "%s@%s" % (user, host))
################### mail access ##################################
[docs]def message(sender='', to='', cc='', subject='', text='', files=None):
"""Create an email message
'to' and 'cc' can be lists of email addresses (python lists or
strings with comma-separated email adresses.
Returns
-------
EmailMessage
The Email message to be sent.
"""
if isinstance(to, list):
to = ', '.join(to)
if isinstance(cc, list):
cc = ', '.join(cc)
message = EmailMessage()
message["From"] = sender
message["To"] = to
if cc:
message["Cc"] = cc
message["Subject"] = subject
message.set_content(text)
return message
def read_smtpdata(filename):
data = {}
with open(os.path.expanduser(filename)) as fil:
for line in fil:
key, value = line.split(':')
value = value.strip()
if key == 'port':
value = int(value)
data[key] = value
return data
[docs]def send_message(message, sender=None, to=None, smtpdata=None):
"""Send an email message
Parameters
----------
message: :class:`EmailMessage`
The Email message to be sent. :func:`message` can help in creating it.
sender: str
The email address of the sender. If None, it is taken from the From:
field in the **message**.
to: str or list
The adressee(s): either a single email address or a list thereof.
If None, it is taken from the To: field in the **message**.
smtpdata: dict | str
A dict with the data needed to connect to the smtp server, or the
name of a file containing this data.
If None, the following config files are tried in order::
'$HOME/.config/smtp_credentials',
'$HOME/.config/pyformex/smtp_credentials'
The data can (and usually should) contain the following fields:
server: the smtp server (like 'smtp.gmail.com')
port: the port number (like 587 for using TLS)
username: the full user name (like 'john.doe@gmail.com')
password: the password needed for authentication
Leave out username and password if no authentication is required.
Notes
-----
When using smtp.gmail.com as your SMTP server and your account has 2FA
activated (it likely has), you need to set up an App Password and use
that password for authentication. To create an App Password, go to your
Google account settings, select the Security section and 2FA authentication,
then create an App Password. By prefernce store it on a config file like
mentioned above. Make the file read-only for everyone except yourself
(chmod 0600).
"""
if smtpdata is None:
for cfg in ('~/.config/smtp_credentials',
'~/.config/pyformex/smtp_credentials'):
if os.path.exists(os.path.expanduser(cfg)):
smtpdata = cfg
break
if isinstance(smtpdata, str):
data = read_smtpdata(smtpdata)
else:
data = smtpdata
server = data.get('server', 'localhost')
port = data.get('port', 25)
username = data.get('username', None)
password = data.get('password', None)
print(f"Connecting to SMTP {server=}, {port=}, {username=}, {password=}")
# return
if port == 465:
SMTP = smtplib.SMTP_SSL
else:
SMTP = smtplib.SMTP
with SMTP(server, port) as smtpserver:
if port == 587:
smtpserver.starttls()
if username:
smtpserver.login(username, password)
smtpserver.send_message(message, from_addr=sender, to_addrs=to)
##################################################################
def input_message(prompt=True):
print(
"""
This is Bene's simple mail program, version 0.00001.
Enter lines of text, end with CTRL-D (on a blank line).
Include at least one line starting with 'To:'
Include exactly one line starting with 'Subj:'
Optionally include a line starting with 'From:'
Optionally include one or more lines starting with 'CC:'
All other lines will be the text of your message.
"""
)
to = []
cc = []
subj = ''
msg = ''
sender = ''
while True:
try:
s = input()
except EOFError: # user hits CTRL-D on blank line
break
slower = s[:5].lower()
if slower.startswith('to:'):
to.append(s[3:])
elif slower.startswith('cc:'):
cc.append(s[3:])
elif slower.startswith('subj:'):
subj = s[5:]
elif slower.startswith('from:'):
sender = s[5:]
else:
msg += s + '\n'
return to, cc, subj, msg, sender
if __name__ == '__main__':
to, cc, subj, msg, sender = input_message()
if not sender:
sender = os.environ.get('EMAIL', None)
if to and subj and msg and sender:
msg = message(sender, to, cc, subj, msg)
print("\n\n Email message:")
print('-'*40)
print(msg.as_string())
print('-'*40)
if input('\n Shall I send the email now? (y/n)') == 'y':
send_message(msg, sender, to)
print("Mail has been sent!")
else:
print("Mail not sent!")
else:
print("Message can not be sent because of missing fields!")
# End