aboutsummaryrefslogtreecommitdiff
path: root/minimailer-csv
blob: 6bddaf789a901d50b6bc913956cb2d375e327ca7 (plain)
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Send emails according to a CSV input with fields and templating support.
#
# Copyright (C) 2022 Silvio Rhatto <rhatto@riseup.net>
#
# 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 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/>.

# Dependencies
import argparse
import csv
import os, subprocess

class MinimailerCSV:
    """Send emails according to a CSV input with fields and templating support"""

    def __init__(self, args):
        self.args = args
        self.data = []

        if os.path.exists(args.template_file[0]):
            with open(args.template_file[0], 'r') as template_file:
                self.template = template_file.read()
        else:
            raise FileNotFoundError('No such file ' + template_file)

        if os.path.exists(args.csv_file[0]):
            with open(args.csv_file[0], newline='') as csv_file:
                self.csv = csv.DictReader(csv_file,
                        delimiter=args.delimiter,
                        quotechar=args.quotechar,
                        )

                for row in self.csv:
                    self.data.append(row)

        else:
            raise FileNotFoundError('No such file ' + csv_file)

    def send(self):
        for item in self.data:
            print('sending message to {}'.format(item[self.args.recipient_field_address]))

            message = self.template.format(**item)

            with subprocess.Popen('{sendmail} {recipient}'.format(
                message=message,
                sendmail=self.args.sendmail_command,
                recipient=item[self.args.recipient_field_address],
                ), text=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True) as proc:

                proc.stdin.write(message)
                proc.stdin.close()

if __name__ == "__main__":
    """Process from CLI"""

    epilog = """Examples:

      minimailer-csv message.tmpl data.csv --sendmail-command 'msmtp -a default'
      minimailer-csv message.tmpl data.csv --recipient-field-address 'contact'
    """

    description = 'Send emails according to a CSV input with fields and templating support'
    parser      = argparse.ArgumentParser(
                    description=description,
                    epilog=epilog,
                    formatter_class=argparse.RawDescriptionHelpFormatter,
                  )

    parser.add_argument('template_file',       nargs=1,   help='Message template filename')
    parser.add_argument('csv_file',            nargs=1,   help='CSV filename. It\'s required that the first line in the CSV contain the field names.')
    #parser.add_argument('mstmp_account_name', nargs='?', help='MSTMP account name')

    # Defaults
    sendmail_command_default        = '/usr/bin/msmtp -a default'
    recipiend_field_address_default = 'email'
    delimiter_default               = ','
    quotechar_default               = '"'

    parser.add_argument(
            '--sendmail-command',
            help='Sendmail command invocation. Defaults to ' + sendmail_command_default
            )

    parser.add_argument(
            '--recipient-field-address',
            help='Email address field in the CSV file. Defaults to ' + recipiend_field_address_default
            )

    parser.add_argument(
            '--delimiter',
            help='CSV field delimiter. Defaults to' + delimiter_default,
            )

    parser.add_argument(
            '--quotechar',
            help='CSV quotechar. Defaults to' + quotechar_default,
            )

    # Set defaults
    #parser.set_defaults(msmtp_account_name='default')
    parser.set_defaults(sendmail_command=sendmail_command_default)
    parser.set_defaults(recipiend_field_address=recipiend_field_address_default)
    parser.set_defaults(delimiter=delimiter_default)
    parser.set_defaults(quotechar=quotechar_default)

    args = parser.parse_args()

    # Dispatch
    try:
        mailer = MinimailerCSV(args)

        mailer.send()

    except (FileNotFoundError, KeyboardInterrupt, subprocess.SubprocessError) as e:
        print(e)
        exit(1)