Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
D
douban-api-proxy
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
captainwong
douban-api-proxy
Commits
99520d54
Commit
99520d54
authored
Mar 28, 2021
by
Ozzie Isaacs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added ability to send emails via gmail (#1905)
Gmail email sending
parent
e10a8c07
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
219 additions
and
86 deletions
+219
-86
admin.py
cps/admin.py
+13
-6
config_sql.py
cps/config_sql.py
+8
-5
__init__.py
cps/services/__init__.py
+6
-0
gmail.py
cps/services/gmail.py
+80
-0
mail.py
cps/tasks/mail.py
+79
-60
admin.html
cps/templates/admin.html
+27
-14
email_edit.html
cps/templates/email_edit.html
+5
-1
gmail.json
gmail.json
+1
-0
No files found.
cps/admin.py
View file @
99520d54
...
@@ -39,7 +39,7 @@ from sqlalchemy.orm.attributes import flag_modified
...
@@ -39,7 +39,7 @@ from sqlalchemy.orm.attributes import flag_modified
from
sqlalchemy.exc
import
IntegrityError
,
OperationalError
,
InvalidRequestError
from
sqlalchemy.exc
import
IntegrityError
,
OperationalError
,
InvalidRequestError
from
sqlalchemy.sql.expression
import
func
,
or_
from
sqlalchemy.sql.expression
import
func
,
or_
from
.
import
constants
,
logger
,
helper
,
services
,
gmail
from
.
import
constants
,
logger
,
helper
,
services
from
.cli
import
filepicker
from
.cli
import
filepicker
from
.
import
db
,
calibre_db
,
ub
,
web_server
,
get_locale
,
config
,
updater_thread
,
babel
,
gdriveutils
from
.
import
db
,
calibre_db
,
ub
,
web_server
,
get_locale
,
config
,
updater_thread
,
babel
,
gdriveutils
from
.helper
import
check_valid_domain
,
send_test_mail
,
reset_password
,
generate_password_hash
from
.helper
import
check_valid_domain
,
send_test_mail
,
reset_password
,
generate_password_hash
...
@@ -58,7 +58,8 @@ feature_support = {
...
@@ -58,7 +58,8 @@ feature_support = {
'ldap'
:
bool
(
services
.
ldap
),
'ldap'
:
bool
(
services
.
ldap
),
'goodreads'
:
bool
(
services
.
goodreads_support
),
'goodreads'
:
bool
(
services
.
goodreads_support
),
'kobo'
:
bool
(
services
.
kobo
),
'kobo'
:
bool
(
services
.
kobo
),
'updater'
:
constants
.
UPDATER_AVAILABLE
'updater'
:
constants
.
UPDATER_AVAILABLE
,
'gmail'
:
bool
(
services
.
gmail
)
}
}
try
:
try
:
...
@@ -1311,7 +1312,7 @@ def new_user():
...
@@ -1311,7 +1312,7 @@ def new_user():
def
edit_mailsettings
():
def
edit_mailsettings
():
content
=
config
.
get_mail_settings
()
content
=
config
.
get_mail_settings
()
return
render_title_template
(
"email_edit.html"
,
content
=
content
,
title
=
_
(
u"Edit E-mail Server Settings"
),
return
render_title_template
(
"email_edit.html"
,
content
=
content
,
title
=
_
(
u"Edit E-mail Server Settings"
),
page
=
"mailset"
)
page
=
"mailset"
,
feature_support
=
feature_support
)
@
admi
.
route
(
"/admin/mailsettings"
,
methods
=
[
"POST"
])
@
admi
.
route
(
"/admin/mailsettings"
,
methods
=
[
"POST"
])
...
@@ -1320,15 +1321,21 @@ def edit_mailsettings():
...
@@ -1320,15 +1321,21 @@ def edit_mailsettings():
def
update_mailsettings
():
def
update_mailsettings
():
to_save
=
request
.
form
.
to_dict
()
to_save
=
request
.
form
.
to_dict
()
_config_int
(
to_save
,
"mail_server_type"
)
_config_int
(
to_save
,
"mail_server_type"
)
if
to_save
.
get
(
"invalidate
_server
"
):
if
to_save
.
get
(
"invalidate"
):
config
.
mail_gmail_token
=
{}
config
.
mail_gmail_token
=
{}
try
:
try
:
flag_modified
(
config
,
"mail_gmail_token"
)
flag_modified
(
config
,
"mail_gmail_token"
)
except
AttributeError
:
except
AttributeError
:
pass
pass
elif
to_save
.
get
(
"gmail"
):
elif
to_save
.
get
(
"gmail"
):
config
.
mail_gmail_token
=
gmail
.
setup_gmail
(
config
)
try
:
flash
(
_
(
u"G-Mail Account Verification Successfull"
),
category
=
"success"
)
config
.
mail_gmail_token
=
services
.
gmail
.
setup_gmail
(
config
.
mail_gmail_token
)
flash
(
_
(
u"G-Mail Account Verification Successfull"
),
category
=
"success"
)
except
Exception
as
e
:
flash
(
e
,
category
=
"error"
)
log
.
error
(
e
)
return
edit_mailsettings
()
else
:
else
:
_config_string
(
to_save
,
"mail_server"
)
_config_string
(
to_save
,
"mail_server"
)
_config_int
(
to_save
,
"mail_port"
)
_config_int
(
to_save
,
"mail_port"
)
...
...
cps/config_sql.py
View file @
99520d54
...
@@ -249,15 +249,15 @@ class _ConfigSQL(object):
...
@@ -249,15 +249,15 @@ class _ConfigSQL(object):
def
get_mail_server_configured
(
self
):
def
get_mail_server_configured
(
self
):
return
bool
((
self
.
mail_server
!=
constants
.
DEFAULT_MAIL_SERVER
and
self
.
mail_server_type
==
0
)
return
bool
((
self
.
mail_server
!=
constants
.
DEFAULT_MAIL_SERVER
and
self
.
mail_server_type
==
0
)
or
(
self
.
mail_gmail_token
!=
b
""
and
self
.
mail_server_type
==
1
))
or
(
self
.
mail_gmail_token
!=
{}
and
self
.
mail_server_type
==
1
))
def
set_from_dictionary
(
self
,
dictionary
,
field
,
convertor
=
None
,
default
=
None
,
encode
=
None
):
def
set_from_dictionary
(
self
,
dictionary
,
field
,
convertor
=
None
,
default
=
None
,
encode
=
None
):
'''
Possibly updates a field of this object.
"""
Possibly updates a field of this object.
The new value, if present, is grabbed from the given dictionary, and optionally passed through a convertor.
The new value, if present, is grabbed from the given dictionary, and optionally passed through a convertor.
:returns: `True` if the field has changed value
:returns: `True` if the field has changed value
'''
"""
new_value
=
dictionary
.
get
(
field
,
default
)
new_value
=
dictionary
.
get
(
field
,
default
)
if
new_value
is
None
:
if
new_value
is
None
:
# log.debug("_ConfigSQL set_from_dictionary field '%s' not found", field)
# log.debug("_ConfigSQL set_from_dictionary field '%s' not found", field)
...
@@ -308,8 +308,11 @@ class _ConfigSQL(object):
...
@@ -308,8 +308,11 @@ class _ConfigSQL(object):
have_metadata_db
=
os
.
path
.
isfile
(
db_file
)
have_metadata_db
=
os
.
path
.
isfile
(
db_file
)
self
.
db_configured
=
have_metadata_db
self
.
db_configured
=
have_metadata_db
constants
.
EXTENSIONS_UPLOAD
=
[
x
.
lstrip
()
.
rstrip
()
.
lower
()
for
x
in
self
.
config_upload_formats
.
split
(
','
)]
constants
.
EXTENSIONS_UPLOAD
=
[
x
.
lstrip
()
.
rstrip
()
.
lower
()
for
x
in
self
.
config_upload_formats
.
split
(
','
)]
# pylint: disable=access-member-before-definition
if
os
.
environ
.
get
(
'FLASK_DEBUG'
):
logfile
=
logger
.
setup
(
self
.
config_logfile
,
self
.
config_log_level
)
logfile
=
logger
.
setup
(
logger
.
LOG_TO_STDOUT
,
logger
.
logging
.
DEBUG
)
else
:
# pylint: disable=access-member-before-definition
logfile
=
logger
.
setup
(
self
.
config_logfile
,
self
.
config_log_level
)
if
logfile
!=
self
.
config_logfile
:
if
logfile
!=
self
.
config_logfile
:
log
.
warning
(
"Log path
%
s not valid, falling back to default"
,
self
.
config_logfile
)
log
.
warning
(
"Log path
%
s not valid, falling back to default"
,
self
.
config_logfile
)
self
.
config_logfile
=
logfile
self
.
config_logfile
=
logfile
...
...
cps/services/__init__.py
View file @
99520d54
...
@@ -45,3 +45,9 @@ except ImportError as err:
...
@@ -45,3 +45,9 @@ except ImportError as err:
log
.
debug
(
"Cannot import SyncToken, syncing books with Kobo Devices will not work:
%
s"
,
err
)
log
.
debug
(
"Cannot import SyncToken, syncing books with Kobo Devices will not work:
%
s"
,
err
)
kobo
=
None
kobo
=
None
SyncToken
=
None
SyncToken
=
None
try
:
from
.
import
gmail
except
ImportError
as
err
:
log
.
debug
(
"Cannot import Gmail, sending books via G-Mail Accounts will not work:
%
s"
,
err
)
gmail
=
None
cps/gmail.py
→
cps/
services/
gmail.py
View file @
99520d54
from
__future__
import
print_function
from
__future__
import
print_function
import
os.path
import
os.path
from
googleapiclient.discovery
import
build
from
google_auth_oauthlib.flow
import
InstalledAppFlow
from
google_auth_oauthlib.flow
import
InstalledAppFlow
from
google.auth.transport.requests
import
Request
from
google.auth.transport.requests
import
Request
from
googleapiclient.discovery
import
build
from
google.oauth2.credentials
import
Credentials
from
google.oauth2.credentials
import
Credentials
from
.constants
import
BASE_DIR
import
json
from
datetime
import
datetime
from
datetime
import
datetime
import
base64
from
flask_babel
import
gettext
as
_
from
..constants
import
BASE_DIR
from
..
import
logger
subject
=
"Test"
msg
=
"Testnachricht"
sender
=
"matthias1.knopp@googlemail.com"
receiver
=
"matthias.knopp@web.de"
SCOPES
=
[
'https://www.googleapis.com/auth/gmail.send'
]
log
=
logger
.
create
()
def
setup_gmail
(
config
):
SCOPES
=
[
'openid'
,
'https://www.googleapis.com/auth/gmail.send'
,
'https://www.googleapis.com/auth/userinfo.email'
]
token
=
config
.
mail_gmail_token
# if config.mail_gmail_token != "{}"
:
def
setup_gmail
(
token
)
:
# If there are no (valid) credentials available, let the user log in.
# If there are no (valid) credentials available, let the user log in.
creds
=
None
creds
=
None
if
"token"
in
token
:
if
"token"
in
token
:
...
@@ -37,10 +36,13 @@ def setup_gmail(config):
...
@@ -37,10 +36,13 @@ def setup_gmail(config):
if
creds
and
creds
.
expired
and
creds
.
refresh_token
:
if
creds
and
creds
.
expired
and
creds
.
refresh_token
:
creds
.
refresh
(
Request
())
creds
.
refresh
(
Request
())
else
:
else
:
cred_file
=
os
.
path
.
join
(
BASE_DIR
,
'gmail.json'
)
if
not
os
.
path
.
exists
(
cred_file
):
raise
Exception
(
_
(
"Found no valid gmail.json file with OAuth information"
))
flow
=
InstalledAppFlow
.
from_client_secrets_file
(
flow
=
InstalledAppFlow
.
from_client_secrets_file
(
os
.
path
.
join
(
BASE_DIR
,
'gmail.json'
),
SCOPES
)
os
.
path
.
join
(
BASE_DIR
,
'gmail.json'
),
SCOPES
)
creds
=
flow
.
run_local_server
(
port
=
0
)
creds
=
flow
.
run_local_server
(
port
=
0
)
user_info
=
get_user_info
(
creds
)
return
{
return
{
'token'
:
creds
.
token
,
'token'
:
creds
.
token
,
'refresh_token'
:
creds
.
refresh_token
,
'refresh_token'
:
creds
.
refresh_token
,
...
@@ -49,16 +51,30 @@ def setup_gmail(config):
...
@@ -49,16 +51,30 @@ def setup_gmail(config):
'client_secret'
:
creds
.
client_secret
,
'client_secret'
:
creds
.
client_secret
,
'scopes'
:
creds
.
scopes
,
'scopes'
:
creds
.
scopes
,
'expiry'
:
creds
.
expiry
.
isoformat
(),
'expiry'
:
creds
.
expiry
.
isoformat
(),
'email'
:
user_info
}
}
# implement your storage logic here, e.g. just good old json.dump() / json.load()
def
get_user_info
(
credentials
):
user_info_service
=
build
(
serviceName
=
'oauth2'
,
version
=
'v2'
,
credentials
=
credentials
)
user_info
=
user_info_service
.
userinfo
()
.
get
()
.
execute
()
return
user_info
.
get
(
'email'
,
""
)
def
send_messsage
(
token
,
msg
):
creds
=
Credentials
(
token
=
token
[
'token'
],
refresh_token
=
token
[
'refresh_token'
],
token_uri
=
token
[
'token_uri'
],
client_id
=
token
[
'client_id'
],
client_secret
=
token
[
'client_secret'
],
scopes
=
token
[
'scopes'
],
)
creds
.
expiry
=
datetime
.
fromisoformat
(
token
[
'expiry'
])
if
creds
and
creds
.
expired
and
creds
.
refresh_token
:
creds
.
refresh
(
Request
())
service
=
build
(
'gmail'
,
'v1'
,
credentials
=
creds
)
message_as_bytes
=
msg
.
as_bytes
()
# the message should converted from string to bytes.
message_as_base64
=
base64
.
urlsafe_b64encode
(
message_as_bytes
)
# encode in base64 (printable letters coding)
raw
=
message_as_base64
.
decode
()
# convert to something JSON serializable
body
=
{
'raw'
:
raw
}
# service = build('gmail', 'v1', credentials=creds)
(
service
.
users
()
.
messages
()
.
send
(
userId
=
'me'
,
body
=
body
)
.
execute
())
# message = MIMEText(msg)
# message['to'] = receiver
# message['from'] = sender
# message['subject'] = subject
# raw = base64.urlsafe_b64encode(message.as_bytes())
# raw = raw.decode()
# body = {'raw' : raw}
# message = (service.users().messages().send(userId='me', body=body).execute())
cps/tasks/mail.py
View file @
99520d54
...
@@ -4,6 +4,8 @@ import os
...
@@ -4,6 +4,8 @@ import os
import
smtplib
import
smtplib
import
threading
import
threading
import
socket
import
socket
import
mimetypes
import
base64
try
:
try
:
from
StringIO
import
StringIO
from
StringIO
import
StringIO
...
@@ -16,11 +18,14 @@ except ImportError:
...
@@ -16,11 +18,14 @@ except ImportError:
from
email.mime.multipart
import
MIMEMultipart
from
email.mime.multipart
import
MIMEMultipart
from
email.mime.text
import
MIMEText
from
email.mime.text
import
MIMEText
from
email
import
encoders
from
email
import
encoders
from
email.utils
import
formatdate
,
make_msgid
from
email.utils
import
formatdate
,
make_msgid
from
email.generator
import
Generator
from
email.generator
import
Generator
from
cps.services.worker
import
CalibreTask
from
cps.services.worker
import
CalibreTask
from
cps.services
import
gmail
from
cps
import
logger
,
config
from
cps
import
logger
,
config
from
cps
import
gdriveutils
from
cps
import
gdriveutils
...
@@ -98,7 +103,7 @@ class EmailSSL(EmailBase, smtplib.SMTP_SSL):
...
@@ -98,7 +103,7 @@ class EmailSSL(EmailBase, smtplib.SMTP_SSL):
class
TaskEmail
(
CalibreTask
):
class
TaskEmail
(
CalibreTask
):
def
__init__
(
self
,
subject
,
filepath
,
attachment
,
settings
,
recipient
,
taskMessage
,
text
,
internal
=
False
):
def
__init__
(
self
,
subject
,
filepath
,
attachment
,
settings
,
recipient
,
taskMessage
,
text
):
super
(
TaskEmail
,
self
)
.
__init__
(
taskMessage
)
super
(
TaskEmail
,
self
)
.
__init__
(
taskMessage
)
self
.
subject
=
subject
self
.
subject
=
subject
self
.
attachment
=
attachment
self
.
attachment
=
attachment
...
@@ -107,70 +112,38 @@ class TaskEmail(CalibreTask):
...
@@ -107,70 +112,38 @@ class TaskEmail(CalibreTask):
self
.
recipent
=
recipient
self
.
recipent
=
recipient
self
.
text
=
text
self
.
text
=
text
self
.
asyncSMTP
=
None
self
.
asyncSMTP
=
None
self
.
results
=
dict
()
self
.
results
=
dict
()
def
prepare_message
(
self
):
def
prepare_message
(
self
):
msg
=
MIMEMultipart
()
message
=
MIMEMultipart
()
msg
[
'Subject'
]
=
self
.
subject
message
[
'to'
]
=
self
.
recipent
msg
[
'Message-Id'
]
=
make_msgid
(
'calibre-web'
)
message
[
'from'
]
=
self
.
settings
[
"mail_from"
]
msg
[
'Date'
]
=
formatdate
(
localtime
=
True
)
message
[
'subject'
]
=
self
.
subject
message
[
'Message-Id'
]
=
make_msgid
(
'calibre-web'
)
message
[
'Date'
]
=
formatdate
(
localtime
=
True
)
text
=
self
.
text
text
=
self
.
text
msg
.
attach
(
MIMEText
(
text
.
encode
(
'UTF-8'
),
'plain'
,
'UTF-8'
))
msg
=
MIMEText
(
text
.
encode
(
'UTF-8'
),
'plain'
,
'UTF-8'
)
message
.
attach
(
msg
)
if
self
.
attachment
:
if
self
.
attachment
:
result
=
self
.
_get_attachment
(
self
.
filepath
,
self
.
attachment
)
result
=
self
.
_get_attachment
(
self
.
filepath
,
self
.
attachment
)
if
result
:
if
result
:
m
sg
.
attach
(
result
)
m
essage
.
attach
(
result
)
else
:
else
:
self
.
_handleError
(
u"Attachment not found"
)
self
.
_handleError
(
u"Attachment not found"
)
return
return
return
message
msg
[
'From'
]
=
self
.
settings
[
"mail_from"
]
msg
[
'To'
]
=
self
.
recipent
# convert MIME message to string
fp
=
StringIO
()
gen
=
Generator
(
fp
,
mangle_from_
=
False
)
gen
.
flatten
(
msg
)
return
fp
.
getvalue
()
def
run
(
self
,
worker_thread
):
def
run
(
self
,
worker_thread
):
# create MIME message
# create MIME message
msg
=
self
.
prepare_message
()
msg
=
self
.
prepare_message
()
use_ssl
=
int
(
self
.
settings
.
get
(
'mail_use_ssl'
,
0
))
try
:
try
:
# send email
if
self
.
settings
[
'mail_server_type'
]
==
0
:
timeout
=
600
# set timeout to 5mins
self
.
send_standard_email
(
msg
)
# redirect output to logfile on python2 on python3 debugoutput is caught with overwritten
# _print_debug function
if
sys
.
version_info
<
(
3
,
0
):
org_smtpstderr
=
smtplib
.
stderr
smtplib
.
stderr
=
logger
.
StderrLogger
(
'worker.smtp'
)
if
use_ssl
==
2
:
self
.
asyncSMTP
=
EmailSSL
(
self
.
settings
[
"mail_server"
],
self
.
settings
[
"mail_port"
],
timeout
=
timeout
)
else
:
else
:
self
.
asyncSMTP
=
Email
(
self
.
settings
[
"mail_server"
],
self
.
settings
[
"mail_port"
],
timeout
=
timeout
)
self
.
send_gmail_email
(
msg
)
except
MemoryError
as
e
:
# link to logginglevel
if
logger
.
is_debug_enabled
():
self
.
asyncSMTP
.
set_debuglevel
(
1
)
if
use_ssl
==
1
:
self
.
asyncSMTP
.
starttls
()
if
self
.
settings
[
"mail_password"
]:
self
.
asyncSMTP
.
login
(
str
(
self
.
settings
[
"mail_login"
]),
str
(
self
.
settings
[
"mail_password"
]))
self
.
asyncSMTP
.
sendmail
(
self
.
settings
[
"mail_from"
],
self
.
recipent
,
msg
)
self
.
asyncSMTP
.
quit
()
self
.
_handleSuccess
()
if
sys
.
version_info
<
(
3
,
0
):
smtplib
.
stderr
=
org_smtpstderr
except
(
MemoryError
)
as
e
:
log
.
debug_or_exception
(
e
)
log
.
debug_or_exception
(
e
)
self
.
_handleError
(
u'MemoryError sending email:
'
+
str
(
e
))
self
.
_handleError
(
u'MemoryError sending email:
{}'
.
format
(
str
(
e
)
))
except
(
smtplib
.
SMTPException
,
smtplib
.
SMTPAuthenticationError
)
as
e
:
except
(
smtplib
.
SMTPException
,
smtplib
.
SMTPAuthenticationError
)
as
e
:
log
.
debug_or_exception
(
e
)
log
.
debug_or_exception
(
e
)
if
hasattr
(
e
,
"smtp_error"
):
if
hasattr
(
e
,
"smtp_error"
):
...
@@ -181,11 +154,54 @@ class TaskEmail(CalibreTask):
...
@@ -181,11 +154,54 @@ class TaskEmail(CalibreTask):
text
=
'
\n
'
.
join
(
e
.
args
)
text
=
'
\n
'
.
join
(
e
.
args
)
else
:
else
:
text
=
''
text
=
''
self
.
_handleError
(
u'Smtplib Error sending email: '
+
text
)
self
.
_handleError
(
u'Smtplib Error sending email: {}'
.
format
(
text
))
except
(
socket
.
error
)
as
e
:
except
socket
.
error
as
e
:
log
.
debug_or_exception
(
e
)
self
.
_handleError
(
u'Socket Error sending email: {}'
.
format
(
e
.
strerror
))
except
Exception
as
e
:
log
.
debug_or_exception
(
e
)
log
.
debug_or_exception
(
e
)
self
.
_handleError
(
u'Socket Error sending email: '
+
e
.
strerror
)
self
.
_handleError
(
u'Error sending email: {}'
.
format
(
e
))
def
send_standard_email
(
self
,
msg
):
use_ssl
=
int
(
self
.
settings
.
get
(
'mail_use_ssl'
,
0
))
timeout
=
600
# set timeout to 5mins
# redirect output to logfile on python2 on python3 debugoutput is caught with overwritten
# _print_debug function
if
sys
.
version_info
<
(
3
,
0
):
org_smtpstderr
=
smtplib
.
stderr
smtplib
.
stderr
=
logger
.
StderrLogger
(
'worker.smtp'
)
if
use_ssl
==
2
:
self
.
asyncSMTP
=
EmailSSL
(
self
.
settings
[
"mail_server"
],
self
.
settings
[
"mail_port"
],
timeout
=
timeout
)
else
:
self
.
asyncSMTP
=
Email
(
self
.
settings
[
"mail_server"
],
self
.
settings
[
"mail_port"
],
timeout
=
timeout
)
# link to logginglevel
if
logger
.
is_debug_enabled
():
self
.
asyncSMTP
.
set_debuglevel
(
1
)
if
use_ssl
==
1
:
self
.
asyncSMTP
.
starttls
()
if
self
.
settings
[
"mail_password"
]:
self
.
asyncSMTP
.
login
(
str
(
self
.
settings
[
"mail_login"
]),
str
(
self
.
settings
[
"mail_password"
]))
# Convert message to something to send
fp
=
StringIO
()
gen
=
Generator
(
fp
,
mangle_from_
=
False
)
gen
.
flatten
(
msg
)
self
.
asyncSMTP
.
sendmail
(
self
.
settings
[
"mail_from"
],
self
.
recipent
,
fp
.
getvalue
())
self
.
asyncSMTP
.
quit
()
self
.
_handleSuccess
()
if
sys
.
version_info
<
(
3
,
0
):
smtplib
.
stderr
=
org_smtpstderr
def
send_gmail_email
(
self
,
message
):
return
gmail
.
send_messsage
(
self
.
settings
.
get
(
'mail_gmail_token'
,
None
),
message
)
@
property
@
property
def
progress
(
self
):
def
progress
(
self
):
...
@@ -205,13 +221,13 @@ class TaskEmail(CalibreTask):
...
@@ -205,13 +221,13 @@ class TaskEmail(CalibreTask):
@
classmethod
@
classmethod
def
_get_attachment
(
cls
,
bookpath
,
filename
):
def
_get_attachment
(
cls
,
bookpath
,
filename
):
"""Get file as MIMEBase message"""
"""Get file as MIMEBase message"""
calibrepath
=
config
.
config_calibre_dir
calibre
_
path
=
config
.
config_calibre_dir
if
config
.
config_use_google_drive
:
if
config
.
config_use_google_drive
:
df
=
gdriveutils
.
getFileFromEbooksFolder
(
bookpath
,
filename
)
df
=
gdriveutils
.
getFileFromEbooksFolder
(
bookpath
,
filename
)
if
df
:
if
df
:
datafile
=
os
.
path
.
join
(
calibrepath
,
bookpath
,
filename
)
datafile
=
os
.
path
.
join
(
calibre
_
path
,
bookpath
,
filename
)
if
not
os
.
path
.
exists
(
os
.
path
.
join
(
calibrepath
,
bookpath
)):
if
not
os
.
path
.
exists
(
os
.
path
.
join
(
calibre
_
path
,
bookpath
)):
os
.
makedirs
(
os
.
path
.
join
(
calibrepath
,
bookpath
))
os
.
makedirs
(
os
.
path
.
join
(
calibre
_
path
,
bookpath
))
df
.
GetContentFile
(
datafile
)
df
.
GetContentFile
(
datafile
)
else
:
else
:
return
None
return
None
...
@@ -221,19 +237,22 @@ class TaskEmail(CalibreTask):
...
@@ -221,19 +237,22 @@ class TaskEmail(CalibreTask):
os
.
remove
(
datafile
)
os
.
remove
(
datafile
)
else
:
else
:
try
:
try
:
file_
=
open
(
os
.
path
.
join
(
calibrepath
,
bookpath
,
filename
),
'rb'
)
file_
=
open
(
os
.
path
.
join
(
calibre
_
path
,
bookpath
,
filename
),
'rb'
)
data
=
file_
.
read
()
data
=
file_
.
read
()
file_
.
close
()
file_
.
close
()
except
IOError
as
e
:
except
IOError
as
e
:
log
.
debug_or_exception
(
e
)
log
.
debug_or_exception
(
e
)
log
.
error
(
u'The requested file could not be read. Maybe wrong permissions?'
)
log
.
error
(
u'The requested file could not be read. Maybe wrong permissions?'
)
return
None
return
None
# Set mimetype
attachment
=
MIMEBase
(
'application'
,
'octet-stream'
)
content_type
,
encoding
=
mimetypes
.
guess_type
(
filename
)
if
content_type
is
None
or
encoding
is
not
None
:
content_type
=
'application/octet-stream'
main_type
,
sub_type
=
content_type
.
split
(
'/'
,
1
)
attachment
=
MIMEBase
(
main_type
,
sub_type
)
attachment
.
set_payload
(
data
)
attachment
.
set_payload
(
data
)
encoders
.
encode_base64
(
attachment
)
encoders
.
encode_base64
(
attachment
)
attachment
.
add_header
(
'Content-Disposition'
,
'attachment'
,
attachment
.
add_header
(
'Content-Disposition'
,
'attachment'
,
filename
=
filename
)
filename
=
filename
)
return
attachment
return
attachment
@
property
@
property
...
...
cps/templates/admin.html
View file @
99520d54
...
@@ -55,29 +55,42 @@
...
@@ -55,29 +55,42 @@
<div
class=
"col"
>
<div
class=
"col"
>
<h2>
{{_('E-mail Server Settings')}}
</h2>
<h2>
{{_('E-mail Server Settings')}}
</h2>
{% if config.get_mail_server_configured() %}
{% if config.get_mail_server_configured() %}
<div
class=
"col-xs-12 col-sm-12"
>
{% if email.mail_server_type == 0 %}
<div
class=
"row"
>
<div
class=
"col-xs-12 col-sm-12"
>
<div
class=
"row"
>
<div
class=
"col-xs-6 col-sm-3"
>
{{_('SMTP Hostname')}}
</div>
<div
class=
"col-xs-6 col-sm-3"
>
{{_('SMTP Hostname')}}
</div>
<div
class=
"col-xs-6 col-sm-3"
>
{{email.mail_server}}
</div>
<div
class=
"col-xs-6 col-sm-3"
>
{{email.mail_server}}
</div>
</div>
</div>
<div
class=
"row"
>
<div
class=
"row"
>
<div
class=
"col-xs-6 col-sm-3"
>
{{_('SMTP Port')}}
</div>
<div
class=
"col-xs-6 col-sm-3"
>
{{_('SMTP Port')}}
</div>
<div
class=
"col-xs-6 col-sm-3"
>
{{email.mail_port}}
</div>
<div
class=
"col-xs-6 col-sm-3"
>
{{email.mail_port}}
</div>
</div>
</div>
<div
class=
"row"
>
<div
class=
"row"
>
<div
class=
"col-xs-6 col-sm-3"
>
{{_('Encryption')}}
</div>
<div
class=
"col-xs-6 col-sm-3"
>
{{_('Encryption')}}
</div>
<div
class=
"col-xs-6 col-sm-3"
>
{{ display_bool_setting(email.mail_use_ssl) }}
</div>
<div
class=
"col-xs-6 col-sm-3"
>
{{ display_bool_setting(email.mail_use_ssl) }}
</div>
</div>
<div
class=
"row"
>
<div
class=
"col-xs-6 col-sm-3"
>
{{_('SMTP Login')}}
</div>
<div
class=
"col-xs-6 col-sm-3"
>
{{email.mail_login}}
</div>
</div>
<div
class=
"row"
>
<div
class=
"col-xs-6 col-sm-3"
>
{{_('From E-mail')}}
</div>
<div
class=
"col-xs-6 col-sm-3"
>
{{email.mail_from}}
</div>
</div>
</div>
</div>
<div
class=
"row"
>
{% else %}
<div
class=
"col-xs-6 col-sm-3"
>
{{_('SMTP Login')}}
</div>
<div
class=
"col-xs-12 col-sm-12"
>
<div
class=
"col-xs-6 col-sm-3"
>
{{email.mail_login}}
</div>
<div
class=
"row"
>
</div>
<div
class=
"col-xs-6 col-sm-3"
>
{{_('E-Mail Service')}}
</div>
<div
class=
"row"
>
<div
class=
"col-xs-6 col-sm-3"
>
{{_('Gmail via Oauth2')}}
</div>
<div
class=
"col-xs-6 col-sm-3"
>
{{_('From E-mail')}}
</div>
</div>
<div
class=
"col-xs-6 col-sm-3"
>
{{email.mail_from}}
</div>
<div
class=
"row"
>
<div
class=
"col-xs-6 col-sm-3"
>
{{_('From E-mail')}}
</div>
<div
class=
"col-xs-6 col-sm-3"
>
{{email.mail_gmail_token['email']}}
</div>
</div>
</div>
</div>
</div>
{% endif %}
{% endif %}
{% endif %}
<a
class=
"btn btn-default emailconfig"
id=
"admin_edit_email"
href=
"{{url_for('admin.edit_mailsettings')}}"
>
{{_('Edit E-mail Server Settings')}}
</a>
<a
class=
"btn btn-default emailconfig"
id=
"admin_edit_email"
href=
"{{url_for('admin.edit_mailsettings')}}"
>
{{_('Edit E-mail Server Settings')}}
</a>
</div>
</div>
</div>
</div>
...
...
cps/templates/email_edit.html
View file @
99520d54
...
@@ -7,6 +7,7 @@
...
@@ -7,6 +7,7 @@
<div
class=
"discover"
>
<div
class=
"discover"
>
<h1>
{{title}}
</h1>
<h1>
{{title}}
</h1>
<form
role=
"form"
class=
"col-md-10 col-lg-6"
method=
"POST"
>
<form
role=
"form"
class=
"col-md-10 col-lg-6"
method=
"POST"
>
{% if feature_support['gmail'] %}
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<label
for=
"mail_server_type"
>
{{_('Choose Server Type')}}
</label>
<label
for=
"mail_server_type"
>
{{_('Choose Server Type')}}
</label>
<select
name=
"mail_server_type"
id=
"config_email_type"
class=
"form-control"
data-control=
"email-settings"
>
<select
name=
"mail_server_type"
id=
"config_email_type"
class=
"form-control"
data-control=
"email-settings"
>
...
@@ -24,6 +25,7 @@
...
@@ -24,6 +25,7 @@
</div>
</div>
</div>
</div>
<div
data-related=
"email-settings-0"
>
<div
data-related=
"email-settings-0"
>
{% endif %}
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<label
for=
"mail_server"
>
{{_('SMTP Hostname')}}
</label>
<label
for=
"mail_server"
>
{{_('SMTP Hostname')}}
</label>
<input
type=
"text"
class=
"form-control"
name=
"mail_server"
id=
"mail_server"
value=
"{{content.mail_server}}"
required
>
<input
type=
"text"
class=
"form-control"
name=
"mail_server"
id=
"mail_server"
value=
"{{content.mail_server}}"
required
>
...
@@ -61,8 +63,10 @@
...
@@ -61,8 +63,10 @@
</div>
</div>
<button
type=
"submit"
name=
"submit"
value=
"submit"
class=
"btn btn-default"
>
{{_('Save')}}
</button>
<button
type=
"submit"
name=
"submit"
value=
"submit"
class=
"btn btn-default"
>
{{_('Save')}}
</button>
<button
type=
"submit"
name=
"test"
value=
"test"
class=
"btn btn-default"
>
{{_('Save and Send Test E-mail')}}
</button>
<button
type=
"submit"
name=
"test"
value=
"test"
class=
"btn btn-default"
>
{{_('Save and Send Test E-mail')}}
</button>
{% if feature_support['gmail'] %}
</div>
</div>
<a
href=
"{{ url_for('admin.admin') }}"
id=
"back"
class=
"btn btn-default"
>
{{_('Cancel')}}
</a>
{% endif %}
<a
href=
"{{ url_for('admin.admin') }}"
id=
"back"
class=
"btn btn-default"
>
{{_('Back')}}
</a>
</form>
</form>
{% if g.allow_registration %}
{% if g.allow_registration %}
<div
class=
"col-md-10 col-lg-6"
>
<div
class=
"col-md-10 col-lg-6"
>
...
...
gmail.json
0 → 100644
View file @
99520d54
{
"installed"
:{
"client_id"
:
"686643671665-uglhp9pmlvjhsoq5q0528cttd16krgpj.apps.googleusercontent.com"
,
"project_id"
:
"calibre-web-260207"
,
"auth_uri"
:
"https://accounts.google.com/o/oauth2/auth"
,
"token_uri"
:
"https://oauth2.googleapis.com/token"
,
"auth_provider_x509_cert_url"
:
"https://www.googleapis.com/oauth2/v1/certs"
,
"client_secret"
:
"hbLugwKAw0xqMctO1KZuhRKy"
}}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment