This repository has been archived by the owner on Nov 8, 2021. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathsendKindle.py
executable file
·224 lines (188 loc) · 7.57 KB
/
sendKindle.py
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
#!/usr/bin/python3
'''
CLI tool for sending files via email to your Kindle device.
You need to have a working IMAP account.
This script is originally based on:
http://rakesh.fedorapeople.org/misc/pykindle.py (Public Domain)
Author: Kamil Páral <https://github.com/kparal/sendKindle>
License: GNU AGPLv3+, see LICENSE file
'''
import configparser
import getpass
import optparse
import os
import smtplib
import sys
import traceback
from io import StringIO
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.generator import Generator
_version = '3'
class SendKindle:
smtp_server = None
smtp_port = 0
smtp_login = None
user_email = None
kindle_email = None
smtp_password = None
convert = False
parser = None
files = []
conffile = os.path.expanduser('~/.config/sendKindle/sendKindle.cfg')
sample_conf = '''[Default]
smtp_server = smtp.gmail.com
smtp_port = 465
smtp_login = username
user_email = [email protected]
kindle_email = [email protected]
# optional
smtp_password = password
convert = False'''
def __init__(self):
self.parse_args()
self.read_config()
self.check_args()
def create_config(self):
'''Creates an empty config file from the template if no config file
exists. Halts program execution in that case. Otherwise nothing
happens.'''
try:
if not os.path.exists(self.conffile):
# create directory
parent = os.path.dirname(self.conffile)
if not os.path.exists(parent):
os.makedirs(parent)
# create file
f = open(self.conffile, 'w')
f.write(self.sample_conf)
f.close()
else:
return
except IOError:
traceback.print_exc()
message = ('Error creating a new config file, maybe wrong '
'permissions?')
print(message, file=sys.stderr)
sys.exit(4)
else:
message = ('A new config file created in: %s\n'
'Please edit it, provide correct values and run the program '
'again.' % self.conffile)
print(message, file=sys.stderr)
sys.exit(5)
def read_config(self):
'''Parse the config file. Create a new one if needed.'''
self.create_config()
config = configparser.SafeConfigParser()
try:
if not config.read([self.conffile]):
raise IOError('%s could not be read' % self.conffile)
self.smtp_server = config.get('Default', 'smtp_server')
self.smtp_port = config.getint('Default', 'smtp_port')
self.smtp_login = config.get('Default', 'smtp_login')
self.user_email = config.get('Default', 'user_email')
self.kindle_email = config.get('Default', 'kindle_email')
if config.has_option('Default', 'smtp_password'):
# prefer value from cmdline option
self.smtp_password = (self.smtp_password or
config.get('Default', 'smtp_password'))
if config.has_option('Default', 'convert'):
# prefer value from cmdline option
self.convert = (self.convert or
config.getboolean('Default', 'convert'))
except (IOError, configparser.Error, ValueError):
traceback.print_exc()
message = ("Your config file could not be read or contains "
"invalid values: %s" % self.conffile)
print(message, file=sys.stderr)
sys.exit(3)
def parse_args(self):
usage = ('Usage: %prog [options] FILE...\n'
' FILE is a file to be sent as an email attachment.')
description = ('SendKindle will send any number of files via email '
'to your Kindle device.')
parser = optparse.OptionParser(usage=usage, version=_version,
description=description)
self.parser = parser
parser.add_option('--password', help=('Use provided password instead '
'of smtp_password value from your config file. If you provide '
"neither of these, you'll be asked interactively."))
parser.add_option('-c', '--convert', action='store_true',
default=False, help=('Ask Kindle service to convert the documents '
'to Kindle format (mainly for PDFs) [default: %default]'))
(options, args) = parser.parse_args()
self.convert = options.convert
if options.password:
self.smtp_password = options.password
if not args:
parser.error('No files provided as arguments! See --help.')
self.files = args
def check_args(self):
if not self.smtp_password:
self.smtp_password = getpass.getpass('Password for %s: '
% self.user_email)
def send_mail(self):
'''Send email with attachments'''
# create MIME message
msg = MIMEMultipart()
msg['From'] = self.user_email
msg['To'] = self.kindle_email
msg['Subject'] = 'Convert' if self.convert else 'Sent to Kindle'
text = 'This email has been automatically sent by SendKindle tool.'
msg.attach(MIMEText(text))
# attach files
for file_path in self.files:
msg.attach(self.get_attachment(file_path))
# convert MIME message to string
fp = StringIO()
gen = Generator(fp, mangle_from_=False)
gen.flatten(msg)
msg = fp.getvalue()
# send email
try:
if self.smtp_port == 587:
mail_server = smtplib.SMTP(host=self.smtp_server, port=self.smtp_port)
mail_server.starttls()
else:
mail_server = smtplib.SMTP_SSL(host=self.smtp_server, port=self.smtp_port)
mail_server.login(self.smtp_login, self.smtp_password)
mail_server.sendmail(self.user_email, self.kindle_email, msg)
mail_server.close()
except smtplib.SMTPException:
traceback.print_exc()
message = ('Communication with your SMTP server failed. Maybe '
'wrong connection details? Check exception details and '
'your config file: %s' % self.conffile)
print(message, file=sys.stderr)
sys.exit(7)
print('Sent email to %s' % self.kindle_email)
def get_attachment(self, file_path):
'''Get file as MIMEBase message'''
try:
file_ = open(file_path, 'rb')
attachment = MIMEBase('application', 'octet-stream')
attachment.set_payload(file_.read())
file_.close()
encoders.encode_base64(attachment)
attachment.add_header('Content-Disposition', 'attachment',
filename=os.path.basename(file_path))
return attachment
except IOError:
traceback.print_exc()
message = ('The requested file could not be read. Maybe wrong '
'permissions?')
print(message, file=sys.stderr)
sys.exit(6)
def main():
'''Run the main program'''
try:
kindle = SendKindle()
kindle.send_mail()
except KeyboardInterrupt:
print('Program interrupted, exiting...', file=sys.stderr)
sys.exit(10)
if __name__ == '__main__':
main()