awdeorio / mailmerge Goto Github PK
View Code? Open in Web Editor NEWA simple, command line mail merge tool.
License: MIT License
A simple, command line mail merge tool.
License: MIT License
<!doctype html>
<head>
<title> Page Title </title>
<!--Meta Tags-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!--Import Google Icon Font-->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<style type="text/css">
* {
margin: 0;
border: 0;
padding: 0;
}
body {
background-color: black;
background-image: url("frame.png");
background-repeat: no-repeat;
background-position: center top;
}
img {
max-width: 100%;
}
#logo,
#logo-text {
text-align: center;
margin: 2%;
}
#logo-text {
color: Red;
font-family: Arial;
}
</style>
</head>
<body>
<div id="wrapper">
<header>
<div id="logo">
<img src="C:/title.jpg" alt="">
</div>
<div id="logo-text">
<h1>Hey {{name}}</h1>
</div>
<div id="logo">
<img src="dog.jpg">
</div>
</header>
<footer>
</footer>
</div>
<!-- Optional JavaScript -->
</body>
</html>
My image location: C:/dog.jpg
I've tried:
C:/dog.jpg
C://dog.jpg
C:\dog.jpg
C:\dog.jpg
C:dog.jpg
file://c:dog.jpg
None of them seems to work, on mail broken img link is something like:
How can i send images on email from my local files?
This is the email header with attachment . Without attachment is okay
Content-Type: multipart/alternative; boundary="===============6399458286909476=="
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="===============6399458286909476=="
SUBJECT: Testing mailmerge
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
FROM: User [email protected]
TO: [email protected]
Date: Mon, 18 May 2020 18:21:03 -0000
It would be nice to add a small number of test cases that use a live SMTP server. At present, any non-dry-run test cases mock the STMP library calls.
Start an SMTP server in a separate process using a pytest fixture. Something roughly equivalent to this CLI: python -m smtpd -n -c DebuggingServer localhost:1025
. Then a test case would use a server config that connects to localhost:1025
.
https://stackoverflow.com/questions/20349170/socket-error-errno-111-connection-refused
Add a diagram to the README describing the mailmerge
workflow.
I Don know is this is the right way, but I want to know whether it is possible to use an html based mail als template.
It'd be nice to be able to include attachments
Is it possible to add BCC/CC headers to the email template and have them handled intelligently?
When I tested this, they appeared in the message sent to the TO address but did not generate any extra emails to the bcc'd or cc'd addresses.
Ideally, extra emails should be generated by these headers, and the BCC header should mostly not appear in the output emails.
Wait and retry in response to SMTP rate limiting. Include a configuration parameter to set the timeout.
It would be nice to have a mailmerge --resume
option to resume sending emails in the event of a failure.
Along with this, it would makes sense to report the database row number of a sent message. It should correspond to row number when viewing the database CSV file in a spreadsheet program.
Add and verify unicode support in message header, including subject, sender name, and recipient name.
https://en.wikipedia.org/wiki/Unicode_and_email#Unicode_support_in_message_header
EDIT: it's possible that this already works. Add tests:
In python 2.7, the csv module doesn't like non-ascii characters. Can mailmerge work around this? Maybe https://github.com/jdunck/python-unicodecsv is an option?
$ mailmerge --sample; sed -ie 's/Myself/étoile/' mailmerge_database.csv; mailmerge
Creating sample template email mailmerge_template.txt
Creating sample database mailmerge_database.csv
Creating sample config file mailmerge_server.conf
Edit these files, and then run mailmerge again
Traceback (most recent call last):
File "/usr/local/bin/mailmerge", line 9, in <module>
load_entry_point('mailmerge==1.7.2', 'console_scripts', 'mailmerge')()
File "/Library/Python/2.7/site-packages/click-6.7-py2.7.egg/click/core.py", line 722, in __call__
return self.main(*args, **kwargs)
File "/Library/Python/2.7/site-packages/click-6.7-py2.7.egg/click/core.py", line 697, in main
rv = self.invoke(ctx)
File "/Library/Python/2.7/site-packages/click-6.7-py2.7.egg/click/core.py", line 895, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/Library/Python/2.7/site-packages/click-6.7-py2.7.egg/click/core.py", line 535, in invoke
return callback(*args, **kwargs)
File "build/bdist.macosx-10.11-intel/egg/mailmerge/main.py", line 213, in main
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/csv.py", line 108, in next
row = self.reader.next()
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 21: ordinal not in range(128)
Support -V/--version
Hi,
I want to use mailmerge cause you made a great job. But I have a problem with the body of the template. Instead of :
`ATTACHMENT: classes/{{classe}}.xls
Bonjour {{name}},
En tant que PP de la classe de {{classe}}, je t'envoie la liste des codes réseau de tes eleves.
C'est ce code qu'ils utilisent pour ouvrir une session sur les ordinateurs du lycee.
A toi de les distribuer s'ils ne les ont pas deja.
Cordialement,
`
I have :
`ATTACHMENT: classes/2_A.xls
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64
Date: Sat, 31 Aug 2019 15:32:22 -0000
Qm9uam91ciBNaWNoZWwsCgpFbiB0YW50IHF1ZSBQUCBkZSBsYSBjbGFzc2UgZGUgMl9BLCBqZSB0
J2Vudm9pZSBsYSBsaXN0ZSBkZXMgY29kZXMgcsODwqlzZWF1IGRlIHRlcyBlbGV2ZXMuIApDJ2Vz
dCBjZSBjb2RlIHF1J2lscyB1dGlsaXNlbnQgcG91ciBvdXZyaXIgdW5lIHNlc3Npb24gc3VyIGxl
cyBvcmRpbmF0ZXVycyBkdSBseWNlZS4gCkEgdG9pIGRlIGxlcyBkaXN0cmlidWVyIHMnaWxzIG5l
IGxlcyBvbnQgcGFzIGRlamEuCgpDb3JkaWFsZW1lbnQsCgotLSAKTWljaGVsIFZpZW5uZQpBQyAv
IElTTiAvIE5TSSAvIFNJTwpSZWZlcmVudCBudW1lcmlxdWUKTFBPIEJsYWlzZSBQYXNjYWwK
attached /home/vienne/Documents/reseau/classes/2_A.xls
sent message 0 DRY RUN
`
I have been looking but not finding. Do you have any idea? Am I dumb ?
Decode utf-8 messages printed to stdout. The current behavior is to print base64-encoded messages, which are hard to verify.
mailmerge_template.txt
with unicode characters, including emoji.
TO: [email protected]
FROM: [email protected]
Laȝamon 😀 klâwen
mailmerge_database.csv
:
email
[email protected]
mailmerge_server.conf
:
[smtp_server]
host = open-smtp.example.com
port = 25
Running mailmerge results in the following stdout:
$ mailmerge
>>> message 0
TO: [email protected]
FROM: [email protected]
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64
Date: Wed, 18 Dec 2019 15:02:04 -0000
TGHInWFtb24ga2zDondlbg==
>>> sent message 0
>>> Limit was 1 messages. To remove the limit, use the --no-limit option.
>>> This was a dry run. To send messages, use the --no-dry-run option.
Ideally, the output would look like this:
Running mailmerge results in the following stdout:
```console
$ mailmerge
>>> message 0
TO: [email protected]
FROM: [email protected]
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64
Date: Wed, 18 Dec 2019 15:02:04 -0000
Laȝamon 😀 klâwen
>>> sent message 0
>>> Limit was 1 messages. To remove the limit, use the --no-limit option.
>>> This was a dry run. To send messages, use the --no-dry-run option.
test_main.py::test_stdout_utf8
I have installed mailmerge via "sudo pip3 install mailmerge"
I have an UTF-8 template and an ASCII CSV file, when I dry-run:
mailmerge --dry-run --no-limit --template mailmerge/rinnovo_quota_template.txt --config mailmerge/gbiscuolo_server.conf --database /tmp/tempfile.JCuuWP50
all the messages are printed with no errors but when I run the same script using "no-dry-run"
mailmerge --no-dry-run --limit 1 --template mailmerge/rinnovo_quota_template.txt --config mailmerge/gbiscuolo_server.conf --database /tmp/tempfile.JCuuWP50
I get the SMTP password prompt, enter it, and then the following error:
File "/usr/local/bin/mailmerge", line 11, in <module>
sys.exit(main())
File "/usr/lib/python3/dist-packages/click/core.py", line 716, in __call__
return self.main(*args, **kwargs)
File "/usr/lib/python3/dist-packages/click/core.py", line 696, in main
rv = self.invoke(ctx)
File "/usr/lib/python3/dist-packages/click/core.py", line 889, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/usr/lib/python3/dist-packages/click/core.py", line 534, in invoke
return callback(*args, **kwargs)
File "/usr/local/lib/python3.5/dist-packages/mailmerge/main.py", line 231, in main
sendmail(message, config_filename)
File "/usr/local/lib/python3.5/dist-packages/mailmerge/main.py", line 72, in sendmail
smtp.send_message(message)
File "/usr/lib/python3.5/smtplib.py", line 958, in send_message
g.flatten(msg_copy, linesep='\r\n')
File "/usr/lib/python3.5/email/generator.py", line 116, in flatten
self._write(msg)
File "/usr/lib/python3.5/email/generator.py", line 181, in _write
self._dispatch(msg)
File "/usr/lib/python3.5/email/generator.py", line 214, in _dispatch
meth(msg)
File "/usr/lib/python3.5/email/generator.py", line 432, in _handle_text
super(BytesGenerator,self)._handle_text(msg)
File "/usr/lib/python3.5/email/generator.py", line 249, in _handle_text
self._write_lines(payload)
File "/usr/lib/python3.5/email/generator.py", line 155, in _write_lines
self.write(line)
File "/usr/lib/python3.5/email/generator.py", line 406, in write
self._fp.write(s.encode('ascii', 'surrogateescape'))
UnicodeEncodeError: 'ascii' codec can't encode character '\xe8' in position 7: ordinal not in range(128)
I don't know how to solve this issue: is it a problem with mailmerge or with the email library?
best regards
Giovanni
Traceback (most recent call last):
File "/usr/bin/mailmerge", line 11, in
load_entry_point('mailmerge==1.7.0', 'console_scripts', 'mailmerge')()
File "/usr/lib/python3.6/site-packages/click/core.py", line 722, in call
return self.main(*args, **kwargs)
File "/usr/lib/python3.6/site-packages/click/core.py", line 697, in main
rv = self.invoke(ctx)
File "/usr/lib/python3.6/site-packages/click/core.py", line 895, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/usr/lib/python3.6/site-packages/click/core.py", line 535, in invoke
return callback(*args, **kwargs)
File "/usr/lib/python3.6/site-packages/mailmerge/main.py", line 230, in main
sendmail(message, config_filename)
File "/usr/lib/python3.6/site-packages/mailmerge/main.py", line 71, in sendmail
smtp.send_message(message)
File "/usr/lib/python3.6/smtplib.py", line 962, in send_message
g.flatten(msg_copy, linesep='\r\n')
File "/usr/lib/python3.6/email/generator.py", line 116, in flatten
self._write(msg)
File "/usr/lib/python3.6/email/generator.py", line 181, in _write
self._dispatch(msg)
File "/usr/lib/python3.6/email/generator.py", line 214, in _dispatch
meth(msg)
File "/usr/lib/python3.6/email/generator.py", line 432, in _handle_text
super(BytesGenerator,self)._handle_text(msg)
File "/usr/lib/python3.6/email/generator.py", line 249, in _handle_text
self._write_lines(payload)
File "/usr/lib/python3.6/email/generator.py", line 155, in _write_lines
self.write(line)
File "/usr/lib/python3.6/email/generator.py", line 406, in write
self._fp.write(s.encode('ascii', 'surrogateescape'))
UnicodeEncodeError: 'ascii' codec can't encode character '\xfc' in position 15: ordinal not in range(128)
Commit e5b9bff introduced a bug whereby the password is set on the first email, then cleared after that. The end result is that the first email is sent, and the second email fails to send due to an authentication failure.
I've run a scratch EPEL build as part of working on #45
https://koji.fedoraproject.org/koji/taskinfo?taskID=35510263
This is very much NOT READY FOR PRIMETIME
Using the sample, I am getting a chardet error.
$ mailmerge
Traceback (most recent call last):
File "/usr/bin/mailmerge", line 11, in <module>
load_entry_point('mailmerge==1.9', 'console_scripts', 'mailmerge')()
File "/usr/lib/python3.6/site-packages/click/core.py", line 722, in __call__
return self.main(*args, **kwargs)
File "/usr/lib/python3.6/site-packages/click/core.py", line 697, in main
rv = self.invoke(ctx)
File "/usr/lib/python3.6/site-packages/click/core.py", line 895, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/usr/lib/python3.6/site-packages/click/core.py", line 535, in invoke
return callback(*args, **kwargs)
File "/usr/lib/python3.6/site-packages/mailmerge/__main__.py", line 45, in cli
config_filename=config_filename,
File "/usr/lib/python3.6/site-packages/mailmerge/api.py", line 343, in main
(message, sender, recipients) = parsemail(raw_message)
File "/usr/lib/python3.6/site-packages/mailmerge/api.py", line 47, in parsemail
detected = chardet.detect(bytearray(raw_message, "utf-8"))
File "/usr/lib/python3.6/site-packages/chardet/__init__.py", line 25, in detect
raise ValueError('Expected a bytes object, not a unicode object')
ValueError: Expected a bytes object, not a unicode object
Note: I have done only a minimal amount of debugging work so far - but figured I'd open this in case you just happened to know it (it's midnight here). I'll pick this up with or without response as I have time.
The current implementation serializes Python email.Message
objects using the as_string()
method. The documentation suggests using the email.generator.Generator
's flatten()
method instead. One advantage is consistent long line rewrapping.
I'm using mailmerge, using a MySQL database as datasource.
This DB contains data and a number of custom views. Each view queries the data and returns a row for each mail to be sent with mailmerge.
As mailmerge is accepting only CSV file as input (as far as I know), and not a DB view, a little utility bash script
send_to <view> <mail_template>
is executing the DB <view> and generates a transient CSV file containing the selected rows.
The script then calls mailmerge using the path to this CSV file and a Jinja2 <mail_template> as input parameters.
Mailmerge does its job and sends a mail for each line in the CSV file. Perfect!
Sometimes, I need to quickly send a mail to a subset of the mysql <view>. One shot. No need to reuse the query.
I could of course create/alter the DB view, but that's not as agile as I would like and could quickly lead to proliferation of views, all with their own little variations on some 'master' view.
Is is possible to use some Jinja2 tagging in the mail template, that would have as an effect to skip the current record?
Something like:
{% if condition_based_on_current_record -%}
TO: {{email}}
SUBJECT: Interesting mail
FROM: My Self <[email protected]>
Dear {{name}},
You are the lucky recipient of this email.
Best regards,
Me
{% endif -%}
If condition_based_on_current_record is true then the mail is sent.
Otherwise, the sender, recipient and message are all empty, and mailmerge would skip the record.
Thank you.
I would like to embed graphics in the mail. Currently I am able to use graphics by referring to external hosted graphics (using the img tag and src=http://....) . Is it also possible to embed these graphics in the mail?
When sending a mail under arch linux with a pip install and only sending one mail merge it appears to send the message twice.
Also using office 365 smtp server.
It looks like Excel will sometimes save a file with Byte Order Mark (BOM). When the mailmerge database contains a BOM, it can't seem to find the first header key.
mailmerge_template.txt
:
TO: {{email}}
FROM: My Self <[email protected]>
Hello {{name}}
mailmerge_database.csv
:
name,email
My Name,[email protected]
$ file mailmerge_database.csv
mailmerge_database.csv: UTF-8 Unicode (with BOM) text, with CRLF line terminators
Is there a way to provide both an HTML and a plain text template? Thanks!
Log output to file. Change output file with -o/--output
option. Rotate files. Always log when --no-dry-run
causes real emails to be sent.
Use the unittest.mock
library to improve testing. https://docs.python.org/3/library/unittest.mock.html . Remove current hand-rolled smtp_dummy.py
.
Is it possible to insert CSS style elements and use webfonts like https://fonts.googleapis.com/css? in mailmerge?
We should support more options for SMTP connections. At present, end-to-end encryption with SSL is the only option.
# Encrypted, SSL
smtp = smtplib.SMTP_SSL(host, port)
# Unencrypted
smtp = smtplib.SMTP(host, port)
# Upgrade to TLS
smtp = smtplib.SMTP(host, port)
smtp.ehlo()
smtp.starttls()
smtp.ehlo
Is there interest in a flood limit timer? For example, my ISP has a limit of 50 emails in 5 minutes. I'd love to be able to tell mailmerge this so i can just leave a process running. Perhaps something like:
mailmerge ... --pause-count=50 --pause-time=600
--pause-count = Pause after this many emails are sent - default 0
--pause-time = Pause for this long in seconds - default 0
Error condition if either is set to a negative value or if only one is set to a positive value
WDYT?
I am having trouble using mailmerge, because it does not set a date-header. That causes X-Amavis / amavisd to block it as spam. Here are the two types of error I get:
The message WAS NOT relayed to:
<-receiver->:
554 5.6.0 Bounce, id=23674-07 - BAD HEADER
This nondelivery report was generated by the program amavisd-new at host
-receiver-. Our internal reference code for your message is
23674-07/WzRLAsDqSAcp
INVALID HEADER
Missing required header field: "Date"
And
X-Virus-Scanned: amavisd-new at server3533.serverpark.dk
X-Amavis-Alert: BAD HEADER SECTION, Missing required header field: "Date"
mailmerge_template.txt
TO: {{email}}
SUBJECT: Testing mailmerge
FROM: My Self <[email protected]>
Content-Type: text/html; charset="utf-8"
<!doctype html>
<html lang="pt-br">
<head>
<title> Page title </title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style type="text/css">
* {
margin: 0;
border: 0;
padding: 0;
color: red;
font-family: Arial, Helvetica, sans-serif;
}
</style>
</head>
<body>
<h1>ççç ÇÇÇ áéíóú !.</h1>
</body>
</html>
Terminal:
>mailmerge
>>> message 0
TO: [email protected]
SUBJECT: Testing mailmerge
FROM: My Self <[email protected]>
Content-Type: text/html; charset="utf-8"
<!doctype html>
<html lang="pt-br">
<head>
<title> Page title </title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style type="text/css">
* {
margin: 0;
border: 0;
padding: 0;
color: red;
font-family: Arial, Helvetica, sans-serif;
}
</style>
</head>
<body>
<h1>ççç ÇÇÇ áéÃóú !.</h1>
</body>
</html>
>>> encoding utf-8
>>> sent message 0 DRY RUN
>>> No attachments were sent with the emails.
>>> Limit was 1 messages. To remove the limit, use the --no-limit option.
>>> This was a dry run. To send messages, use the --no-dry-run option.
Recieved mail:
Am i doing anything wrong? What should i do to those characters appears?
Template:
From: [email protected]
TO: [email protected]
SUBJECT: Hello
ATTACHMENT: a.txt
CONTENT-TYPE: text/html
<html>
<body>
<p>Hi,</p>
</body>
</html>
command: mailmerge --database database.csv --template 04.tpl --output-format raw
output:
>>> message 1
Content-Type: multipart/alternative;
boundary="===============1872202902524908882=="
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
SUBJECT: Hello
From: [email protected]
TO: [email protected]
Date: Wed, 05 Aug 2020 21:37:21 -0000
--===============1872202902524908882==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
<html>
<body>
<p>Hi,</p>
</body>
</html>
--===============1872202902524908882==
Content-Type: application/octet-stream; Name="a.txt"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="a.txt"
aGVsbG93b3JsZA==
--===============1872202902524908882==--
>>> message 1 sent
>>> Limit was 1 message. To remove the limit, use the --no-limit option.
>>> This was a dry run. To send messages, use the --no-dry-run option.
The important part being Content-Type: text/plain; charset="us-ascii"
, which is incorrect. Using a html+plaintext message works, but that is more complicated.
It would be nice to have unicode support so that users with unicode names could spell them correctly.
I've been looking and it seems we could do this if we always sent a UTF-8 encoded email, easily.
WDYT?
It would be nice to include a line number when the CSV module triggers and error.
From https://docs.python.org/3.4/library/csv.html#examples:
filename = 'some.csv'
with open(filename, newline='') as f:
reader = csv.reader(f)
try:
for row in reader:
print(row)
except csv.Error as e:
sys.exit('file {}, line {}: {}'.format(filename, reader.line_num, e))
Using mailmerge to send mass emails is better than using any gmail extensions, since i have the ability to use advanced markdown and html
however while working with a large (5k+) csv file of job applicants, i came across an issue that people had entered their names in a localized language (eg. mandarin, etc) that sometimes didn't fit the ascii charmaps.
It would be useful to open the csv file as encoding=utf8
with errors=ignore
to avoid errors like this:
'charmap' codec can't decode byte 0x9d in position 1710: character maps to <undefined>
instead of just returning true if strings are ascii.
Traceback (most recent call last):
File "/usr/local/bin/mailmerge", line 11, in <module>
sys.exit(main())
File "/usr/local/lib/python2.7/site-packages/click/core.py", line 716, in __call__
return self.main(*args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/click/core.py", line 696, in main
rv = self.invoke(ctx)
File "/usr/local/lib/python2.7/site-packages/click/core.py", line 889, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/usr/local/lib/python2.7/site-packages/click/core.py", line 534, in invoke
return callback(*args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/mailmerge/main.py", line 182, in main
sendmail(message, config_filename)
File "/usr/local/lib/python2.7/site-packages/mailmerge/main.py", line 51, in sendmail
smtp = smtplib.SMTP_SSL(sendmail.host, sendmail.port)
File "/usr/local/Cellar/python/2.7.12/Frameworks/Python.framework/Versions/2.7/lib/python2.7/smtplib.py", line 801, in __init__
SMTP.__init__(self, host, port, local_hostname, timeout)
File "/usr/local/Cellar/python/2.7.12/Frameworks/Python.framework/Versions/2.7/lib/python2.7/smtplib.py", line 256, in __init__
(code, msg) = self.connect(host, port)
File "/usr/local/Cellar/python/2.7.12/Frameworks/Python.framework/Versions/2.7/lib/python2.7/smtplib.py", line 316, in connect
self.sock = self._get_socket(host, port, self.timeout)
File "/usr/local/Cellar/python/2.7.12/Frameworks/Python.framework/Versions/2.7/lib/python2.7/smtplib.py", line 806, in _get_socket
new_socket = socket.create_connection((host, port), timeout)
File "/usr/local/Cellar/python/2.7.12/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 557, in create_connection
for res in getaddrinfo(host, port, 0, SOCK_STREAM):
socket.error: getaddrinfo() argument 2 must be integer or string
It looks like chardet
doesn't always get the encoding right — in a message containing emoji, chardet
reported (with low confidence) that the message was encoded in Windows-1252. Python throws an exception when trying to encode a string with emoji to that charset.
I don't know if there's a good fix. Can we assume that users are responsible for specifying an encoding if it's not UTF-8? (That would remove our reliance on chardet
.)
Steps I followed on my Mac:
mailmerge_template.txt
:TO: {{email}}
SUBJECT: Testing mailmerge
FROM: My Self <[email protected]>
Hi 😀
mailmerge --dry-run --limit 1
I received this error:
...
File "/Users/seshrs/Documents/Git/mailmerge/mailmerge/template_message.py", line 76, in _transform_encoding
part.set_charset(encoding)
File "/Users/seshrs/Documents/Git/mailmerge/env/lib/python3.7/site-packages/future/backports/email/message.py", line 322, in set_charset
self._payload = charset.body_encode(self._payload)
File "/Users/seshrs/Documents/Git/mailmerge/env/lib/python3.7/site-packages/future/backports/email/charset.py", line 403, in body_encode
string = string.encode(self.output_charset)
File "/usr/local/bin/../Cellar/python/3.7.4_1/bin/../Frameworks/Python.framework/Versions/3.7/lib/python3.7/encodings/cp1252.py", line 12, in encode
return codecs.charmap_encode(input,errors,encoding_table)
UnicodeEncodeError: 'charmap' codec can't encode character '\U0001f600' in position 3: character maps to <undefined>
I set a breakpoint in the _transform_encoding
function:
mailmerge/mailmerge/template_message.py
Lines 66 to 74 in 3a78fbd
And printed the contents of detected
:
(Pdb++) detected
{'encoding': 'Windows-1252', 'confidence': 0.5334615384615384, 'language': ''}
I had expected 'utf-8', not 'Windows-1252'. To confirm this was the issue, I tried executing the following in Python:
>>> "hi 😀".encode('Windows-1252')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/Cellar/python/3.7.4_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/encodings/cp1252.py", line 12, in encode
return codecs.charmap_encode(input,errors,encoding_table)
UnicodeEncodeError: 'charmap' codec can't encode character '\U0001f600' in position 3: character maps to <undefined>
(The call to part.set_charset(encoding)
eventually reaches this line in the python-future
code that executes something like the above.)
Pr #53 added code coverage measurement. At the time of this writing, coverage is around 70%. Improve this by writing more tests.
test_main.py
(formerly test_mailmerge.py
)
test_template_message.py
__init__()
accepts either a filename or file objecttest_sendmail_client.py
__init__()
accepts either a filename or file objectI have tried to use this script to send one mail message to mulitple recepients, but it did't work out. I have tried the following syntaxes:
email, name
"[email protected],[email protected]", "John Doe"
"[email protected], [email protected]", "John Doe"
"[email protected];[email protected]", "John Doe"
"[email protected]; [email protected]", "John Doe"
[email protected]; [email protected], "John Doe"
Bot none of them seem to work.
Great tool! Does exactly what I am looking for.
There is just one Issue when trying to send a multipart message, I am getting this error:
mailmerge --dry-run
>>> message 0
TO: myself@mydomain.com
SUBJECT: Testing mailmerge
FROM: My Self <myself@mydomain.com>
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="outer-boundary"
This is a MIME-encoded message. If you are seeing this, your mail
reader is old.
--outer-boundary
Content-Type: text/plain; charset=us-ascii
Hi, Myself,
Your number is 17.
Sent by mailmerge https://github.com/awdeorio/mailmerge
--outer-boundary
MIME-Version: 1.0
Content-Type: multipart/related;
type="text/html"; start="<body@here>"; boundary="inner-boundary"
--inner-boundary
Content-Type: text/html; charset=us-ascii
Content-Disposition: inline
Content-ID: <body@here>
<html>
<body>
<p>Hi, Myself,</p>
<p>Your number is 17.</p>
<p>Sent by <a href="https://github.com/awdeorio/mailmerge">mailmerge</a></p>
</body>
</html>
Traceback (most recent call last):
File "/usr/local/bin/mailmerge", line 11, in <module>
sys.exit(cli())
File "/usr/local/lib/python2.7/site-packages/click/core.py", line 764, in __call__
return self.main(*args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/click/core.py", line 717, in main
rv = self.invoke(ctx)
File "/usr/local/lib/python2.7/site-packages/click/core.py", line 956, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/usr/local/lib/python2.7/site-packages/click/core.py", line 555, in invoke
return callback(*args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/mailmerge/__main__.py", line 45, in cli
config_filename=config_filename,
File "/usr/local/lib/python2.7/site-packages/mailmerge/api.py", line 238, in main
(text, sender, recipients) = parsemail(raw_message)
File "/usr/local/lib/python2.7/site-packages/mailmerge/api.py", line 39, in parsemail
message.set_charset(encoding)
File "/usr/local/lib/python2.7/site-packages/future/backports/email/message.py", line 320, in set_charset
cte(self)
File "/usr/local/lib/python2.7/site-packages/future/backports/email/encoders.py", line 68, in encode_7or8bit
orig.decode('ascii')
AttributeError: 'list' object has no attribute 'decode'
I have used the --sample flag and copied the multipart example in the Readme.
Working with plain text and pure html emails works.
Any Idea, what this could be? I would be more than happy to help if possible.
The following message should be sent with Content-Type: text/html
. Instead, it is sent as Content-Type: text/plain
.
TO: {{email}}
SUBJECT: Testing mailmerge
FROM: [email protected]
Content-Type: text/html
<html>
<body>
Hello world
</body>
</html>
PR #88 contained a work-around for a bug in future.backports.email.base64mime.header_encode
that raises an exception when serializing an email message object containing a base64-encoded UTF8 header. Remove the work-around in utils.py
after PythonCharmers/python-future#555 is fixed upstream.
Don't forget to bump the dependency library version in setup.py
.
Any thoughts on a interface such tinymce for generating the mailmerge template? Could be particularly useful for generating templates which include both plain text and html. Perhaps out of the scope of this tool but maybe a supplementary tool?
I was wondering if something like this would be possible:
ATTACHMENT: u4qSjQL.jpeg
![](u4qSjQL.jpeg)
I tried it, and it renders to just an image tag: <p><img alt="" src="u4qSjQL.jpeg" /></p></body></html>
Apparently, it is possible via a href that points to the cid
.
Sending a message with special characters gives good results.
TO: {{email}}
SUBJECT: Testing mailmerge
FROM: [email protected]
Hi, {{name}},
æøå
outputs
>>> encoding utf-8
>>> message 0
TO: [email protected]
SUBJECT: Testing mailmerge
FROM: [email protected]
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64
Date: Fri, 13 Dec 2019 20:41:08 -0000
SGksIE15c2VsZiwKw6bDuMOl
Notice that charset
here is set ut utf-8
and message renders well in email client.
But when specifying markdown:
TO: {{email}}
SUBJECT: Testing mailmerge
FROM: [email protected]
CONTENT-TYPE: text/markdown
Hi, {{name}},
æøå
It outputs
>>> encoding utf-8
>>> message 0
MIME-Version: 1.0
SUBJECT: Testing mailmerge
Date: Fri, 13 Dec 2019 20:42:22 -0000
TO: [email protected]
FROM: [email protected]
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Type: multipart/alternative; boundary="===============3629053266709230733=="
--===============3629053266709230733==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
SGksIE15c2VsZiwKw6bDuMOl
--===============3629053266709230733==
Content-Type: text/html; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
<html><body><p>SGksIE15c2VsZiwKw6bDuMOl</p></body></html>
--===============3629053266709230733==--
Notice that charset
here is set ut us-ascii
, and message shows up as SGksIE15c2VsZiwKw6bDuMOl in the client.
PR #32 added a work-around for a bug in future.backports.email.Message.set_boundary
which causes errors when serializing multipart email Message objects in Python 2.
Remove the work-around (_create_boundary(message)
) when the upstream issue is resolved. PythonCharmers/python-future#429
The sh
module seems to be unmaintained (last commit was in 2017) and it is not being tested against the latest Python versions.
As of Python 3.5, much of the functionality in sh
can be replicated with subprocess.run
.
First, verify that a backport exists.
EDIT: The Click library's testing functionality is a better option for many of the tests that currently use sh
. This SO post is helpful.
Instead of rewriting the message, I would like to write the text version in markdown, and have the html version auto-generated. Taking care of the multipart boundaries by hand and rewriting emails in HTML is just 😿
When running mail merge using arch linux with pip install on dry run mode. The terminal returns the text below
TO: ...
SUBJECT: ...
FROM: ....
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64
Date: Thu, 23 Jan 2020 07:37:45 -0000
RGVhciBNcnMgQmVuIGFuZCBNcnMgV2VuZHkgRnJlbmNoCgpJIGFtIGhhcHB5IHRvIGNvbmZpcm0g
dGhhdCBMYXVyZW4gd2lsbCBiZSBpbiBteSBtZW50b3IgZ3JvdXAgdGhpcyB5ZWFyLgpJIHdpbGwg
ZW5kZWF2b3VyIHRvIGd1aWRlIHlvdXIgY2hpbGQgdGhyb3VnaG91dCB0aGUgeWVhciBhcyBzaGUg
ZW1iYXJrcyBvbiB0aGlzIGV4Y2l0aW5nIGpvdXJuZXkuIEkgaGF2ZSB0aGUgcGxlYXN1cmUgb2Yg
c2VlaW5nIExhdXJlbiBpbiBteSBDb21wdXRhdGlvbmFsIFRoaW5raW5nIGNsYXNzLCBhcyB3ZWxs
IGFzIGluIFByb2plY3QgQmFzZWQgTGVhcm5pbmcuIFRoZSBmdW5jdGlvbiBvZiBhIG1lbnRvciBp
cyB0byBndWlkZSBMYXVyZW4gdG8gYmUgc3VjY2Vzc2Z1bCBhbmQgZmVlbCB3ZWxjb21lZCB0byBv
dXIgc2Nob29sLgoKUGxlYXNlIGZlZWwgZnJlZSB0byBjb250YWN0IG1lIHNob3VsZCB5b3UgaGF2
ZSBhbnkgZ2VuZXJhbCBxdWVyaWVzIG9yIHF1ZXN0aW9ucy4KU2hvdWxkIEkgYmUgdW5hYmxlIHRv
IGFuc3dlciBhIHF1ZXN0aW9uLCBJIHdpbGwgZW5zdXJlIHRoYXQgeW91IGFyZSBkaXJlY3RlZCB0
byB0aGUgcmVsZXZhbnQgcGVyc29uLgoKU2hvdWxkIHlvdSB3aXNoIHRvIGVucXVpcmUgYWJvdXQg
YWNhZGVtaWMgbWF0dGVycyBwbGVhc2UgY29udGFjdCB0aGUgc3ViamVjdCB0ZWFjaGVyIGRpcmVj
dGx5LiBEZXRhaWxzIG9mIHRoZSBzdWJqZWN0IHRlYWNoZXJzIGNhbiBiZSBmb3VuZCBpbiBvdXIg
YWNhZGVtaWMgcmVwb3J0aW5nIHN5c3RlbSBhZGFtLnJlZGhpbGwuY28uemEuCgpBbGwgY29tbXVu
aWNhdGlvbiByZWdhcmRpbmcgc3R1ZGVudCB3ZWxsLWJlaW5nIG11c3QgYmUgZGlyZWN0ZWQgdG8g
TXIgTW9yZSAoR3JhZGUgSGVhZCkuIEFkZGl0aW9uYWxseSBwbGVhc2UgQy5DIHRoZSBtZW50b3Ig
aW4gdGhlIGFib3ZlIGNvbW11bmljYXRpb24uIFJlcXVlc3RzIGZvciBwbGFubmVkIGVhcmx5IGRl
cGFydHVyZSBtdXN0IGJlIHNlbnQgdG8gTXIgTW9yZSBiZWZvcmUgMDZoMzAgb3IgYXMgZWFybHkg
YXMgcG9zc2libGUuCgpPdXIgQSZFIHByb2dyYW1tZSBlbnN1cmVzIHRoYXQgeW91ciBjaGlsZCB3
aWxsIHdyaXRlIGEgYmktd2Vla2x5IHN0YW5kYXJkaXNlZCB0ZXN0LiBTaG91bGQgTGF1cmVuIGJl
IGFic2VudCBwbGVhc2UgZW5zdXJlIHRoYXQgYSBkb2N0b3LigJlzIG5vdGUgaXMgc2VudCB0byBN
ciBNb3JlLiBXZSByZWdyZXQgdGhhdCBzdHVkZW50cyB0aGF0IGRvIG5vdCBoYXZlIHN1aXRhYmxl
IGV4Y3VzZXMgd2lsbCByZWNlaXZlIGEgemVyby4KClBsZWFzZSBlbnN1cmUgdGhhdCBMYXVyZW4g
a2VlcHMgdXAgdG8gZGF0ZSB3aXRoIHRoZSBub3RpZmljYXRpb25zIG9uIEdvb2dsZSBDbGFzc3Jv
b20gYXMgd2VsbCBhcyBsaXN0ZW5pbmcgYXR0ZW50aXZlbHkgaW4gb3VyIHNlcGFyYXRlIG1pZGRs
ZSBzY2hvb2wgYXNzZW1ibHkuCgpMYXN0bHksIHBsZWFzZSBlbnN1cmUgdGhhdCB5b3UgYXJlIGFi
bGUgdG8gYWNjZXNzIG91ciBNaVNvY3MgY2FsZW5kYXIgaW4gb3JkZXIgdG8gIGtlZXAgdXAgdG8g
ZGF0ZSB3aXRoIGNhbXB1cyBldmVudHMuCgpLaW5kIFJlZ2FyZHMKTXIgQmVuIEZyZW5jaAoKCg==
sent message 1
Limit was 1 message. To remove the limit, use the --no-limit option.
I just started with mailmerge, fits the job perfectly. One issue I have noticed is mailmerge encountering an email address that the sendmail client function, or the server, rejects. People move jobs or email accounts get deleted from time to time.
Instead of the mailmerge failing out on a bad address, is there a method to log the failures to an error file and keep going through the csv database? Doing a manual resume and specifying the next record on the command-line can be an issue if the job is running in a window you're not monitoring in real-time.
Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.