From 115d3cca0dcddd5c843d000e771e2de275e826a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 May 2018 00:51:53 +0200 Subject: [PATCH] add newmail script --- roles/postfix/files/newmail/newmail | 102 +++++++++++++++++++++++ roles/postfix/files/newmail/templates.py | 26 ++++++ roles/postfix/tasks/postfix.yml | 15 ++++ 3 files changed, 143 insertions(+) create mode 100755 roles/postfix/files/newmail/newmail create mode 100644 roles/postfix/files/newmail/templates.py diff --git a/roles/postfix/files/newmail/newmail b/roles/postfix/files/newmail/newmail new file mode 100755 index 0000000..86a1d99 --- /dev/null +++ b/roles/postfix/files/newmail/newmail @@ -0,0 +1,102 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- +from __future__ import print_function +import sys, os, random, MySQLdb, subprocess, time, string, argparse +import urllib, smtplib, email.mime.text, email.utils +from settings import * +from templates import * + +# setup +random.seed = os.urandom(32) + +# DB stuff +db = MySQLdb.connect(user=DB_USER, passwd=DB_PW, db=DB_NAME, charset='utf8') + +def db_execute(query, args): + cursor = db.cursor(MySQLdb.cursors.DictCursor) + if len(args) == 1 and isinstance(args[0], dict): args = args[0] # einzelnes dict weiterreichen + cursor.execute(query, args) + return cursor + +def db_fetch_one_row(query, *args): + cursor = db_execute(query, args) + result = cursor.fetchone() + if cursor.fetchone() is not None: + raise Exception("Found more than one result, only one was expected") + cursor.close() + return result + +def db_run(query, *args): + cursor = db_execute(query, args) + cursor.close() + +def new_user(name, hash, ): + db_run('INSERT INTO users (username, password, active) VALUES (%s, %s, -1)', name, hash) + +def new_alias(name, alias): + db_run('INSERT INTO aliases (mail, user) VALUES (%s, %s)', name, alias) + +# interaction with dbadm pw +def gen_hash(plain): + return subprocess.check_output(["doveadm", "pw", "-s", "SHA512-CRYPT", "-r", str(64*1024), "-p", plain]).decode('utf-8').strip() + +# more tools +def gen_pw(length = 12): + chars = string.ascii_letters + string.digits + return ''.join(random.choice(chars) for i in range(length)) + +def send_mail(user, mail, password, forward): + assert password is not None, "Sending mail for non-password accounts not yet supported." + incoming = (INCOMING_FORWARD if forward else INCOMING_IMAP).format(password=password, user=user, host=HOST, forward=forward) + text = TEMPLATE.format(password=password, user=user, host=HOST, forward=forward, incoming=incoming) + subject = SUBJECT.format(user=user, host=HOST) + # construct mail content + msg = email.mime.text.MIMEText(text, 'plain', 'utf-8') + msg['Subject'] = subject + msg['Date'] = email.utils.formatdate(localtime=True) + msg['From'] = MAIL_ADDR + msg['To'] = mail + msg['Bcc'] = MAIL_ADDR + # put into envelope and send + s = smtplib.SMTP('localhost') + s.sendmail(MAIL_ADDR, [mail, MAIL_ADDR], msg.as_string()) + s.quit() + +# read command-line arguments +parser = argparse.ArgumentParser(description='Create a new e-mail user') +parser.add_argument("-u", "--username", + dest="username", required=True, + help="The name of the user (that's also its address).") +parser.add_argument("-f", "--forward", + dest="forward", + help="Where to forward emails to.") +#parser.add_argument("-p", "--password", +# action="store_true", dest="password", +# help="Whether to create an account and password for this user.") +parser.add_argument("-m", "--mail", nargs='?', + action="store", dest="mail", const=True, + help="Whether to notify the user about their new account.") +args = parser.parse_args() + +# sanity check +if args.mail == True: + if args.forward: + args.mail = args.forward + else: + print("Whom should I send the mail to? Please use `-m
`.") + sys.exit(1) +domain = args.username.split('@')[-1] +if domain not in DOMAINS: + print("{} is not a domain we can handle mail for.".format(domain)) + sys.exit(1) + +# do stuff +password = gen_pw() +new_user(args.username, gen_hash(password)) +print("Created {} with password {}".format(args.username, password)) +if args.forward: + new_alias(args.username, args.forward) + print("Forwarded {} to {}".format(args.username, args.forward)) +if args.mail: + send_mail(args.username, args.mail, password, args.forward) + print("Sent mail about the new account to {}".format(args.mail)) diff --git a/roles/postfix/files/newmail/templates.py b/roles/postfix/files/newmail/templates.py new file mode 100644 index 0000000..7be7108 --- /dev/null +++ b/roles/postfix/files/newmail/templates.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +SUBJECT = "Deine E-Mail-Adresse {user}" +TEMPLATE = """Hallo, + +du hast jetzt einen E-Mail-Account "{user}" mit Passwort "{password}". +Bevor du dich einloggen kannst, musst du das Passwort unter ändern. + +{incoming} + +Versenden kannst du Mails via SMTP: + Server: {host} + Port: 587 + Verschlüsselung: STARTTLS + Benutzername: {user} + +Bitte prüfe, ob das alles funktioniert. Bei Problemen kannst du dich gerne an mich wenden. + +Viele Grüße, +Ralf""" +INCOMING_FORWARD = "Eingehende Mails werden an deine Adresse {forward} weitergeleitet." +INCOMING_IMAP = '''Der Zugriff auf das Postfach erfolgt via IMAP: + Server: {host} + Port: 143 + Verschlüsselung: STARTTLS + Benutzername: {user}''' + diff --git a/roles/postfix/tasks/postfix.yml b/roles/postfix/tasks/postfix.yml index 4810085..b39f722 100644 --- a/roles/postfix/tasks/postfix.yml +++ b/roles/postfix/tasks/postfix.yml @@ -61,3 +61,18 @@ file: path: /etc/cron.daily/mailman-check state: absent +# tools +- name: create newmail dir + when: postfix.vmail_mysql_password is defined + file: path=/root/newmail state=directory +- name: install newmail script + when: postfix.vmail_mysql_password is defined + copy: + dest: /root/newmail/newmail + src: files/newmail/newmail + mode: u=rwx,g=rx,o=rx +- name: install newmail templates + when: postfix.vmail_mysql_password is defined + copy: + dest: /root/newmail/templates.py + src: files/newmail/templates.py -- 2.30.2