Source code for sendmail

#!/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