teleshoes/qtemail
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Copyright 2015 by Elliot Wolk
This project is free software, released under the GPLv3
smtp-cli Copyright Michal Ludvig 2003-2014
smtp-cli is free software, released under the GPLv3
small changes to smtp-cli Copyright 2015 Elliot Wolk
qmlcompletionbox Copyright 2013 Vyacheslav Blinov
qmlcompletionbox is free software, released under the GPLv2
qmlcompletionbox is based on SuggestionBox.qml from liquid browser
liquid Copyright 2011 Jocelyn Turcotte
liquid is free software, released under the GPLv2
Simple IMAP client with a QT gui and a CLI
Minimal dependencies, currently minimal features
icons:
Blue Magic
by RevZAP
https://www.iconfinder.com/iconsets/blue-magic
WooCons #1
by Janik Baumgartner
http://www.woothemes.com/2010/08/woocons1
Knob Buttons Toolbar icons
by iTweek
http://itweek.deviantart.com/art/Knob-Buttons-Toolbar-icons-73463960
Diagram
by Double-J designs
https://www.iconfinder.com/iconsets/diagram
FILES
src/email-gui.py
simple python QT gui (pyside+QML)
essentially a wrapper around email.pl
should work anywhere QT/python/perl work with little effort
explicitly supported platforms:
Sailfish OS
Debian GNU/Linux
QML is located in /opt/email-gui/
src/email.pl
simple command line IMAP client
caches all headers, and caches unread bodies
e.g.:
> echo "configure $HOME/.secrets first"
configure /home/wolke/.secrets and run 'email.pl'
>
> email.pl
GMail: logging in
fetching all message ids
fetched 15906 ids
caching headers for 15906 messages
caching bodies for 1 messages
>
> email.pl --summary
GMail 2015-01-20 11:10:01 "Naked Girls Reading NYC" <ngrnyc@gmail.com>
Join us tomorrow night for SCIENCE!
>
> email.pl --print
ACCOUNT: GMail
UID: 35870
DATE: Tue, 20 Jan 2015 11:10:01 -0500
FROM: "Naked Girls Reading NYC" <ngrnyc@gmail.com>
SUBJECT: Join us tomorrow night for SCIENCE!
BODY:
This November, the Naked Girls give it all away
as Naked Girls Reading presents SPOILER ALERT!
Join the hit nude literary salon for an evening...
>
> email.pl --unread-line && echo
G1
> email.pl --body G 35870 | grep -o '<div>' | wc -l
0
> email.pl --body-html G 35870 | grep -o '<div>' | wc -l
12
src/email-search.pl
builds and queries a sqlite database for header information like subject/to/from
e.g.:
> email-search.pl --updatedb G inbox all
updatedb: all:19128 cached:19128 uncached:0 adding:0
no UIDs to add
> email-search.pl --search G 'bananas'
23654
23741
23777
src/smtp-cli
SMTP command line client, written by Michal Ludvig
https://github.com/mludvig/smtp-cli
src/bash-complete.pl
helper script that generates bash completion words
bashcompletion/qtemail
bash completion script that invokes bash-complete.pl
~/.secrets
Account config goes here. See "Usage" below.
Dependencies:
perl
perl modules:
Mail::IMAPClient
IO::Socket::SSL
MIME::Parser
Date::Parse
Date::Format
MIME::Lite
python
pyside
qt
qtquick 1.1
sqlite
Usage:
===== email.pl =====
Simple IMAP client. {--smtp command is a convenience wrapper around smtp-cli}
Configuration is in ~/.secrets
Each config entry is one line of the format:
email.GLOBAL_OPTION_KEY = <value>
or
email.ACCOUNT_NAME.ACCOUNT_CONFIG_KEY = <value>
Account names can be any word characters (alphanumeric plus underscore)
Lines that do not begin with "email." are ignored.
ACCOUNT_NAME: the word following "email." in ~/.secrets
FOLDER_NAME: "inbox", "sent" or one of the names from "folders"
UID: an IMAP UID {UIDVALIDITY is assumed to never change}
GLOBAL_OPTION_KEY:
update_cmd [OPT] command to run after all updates
encrypt_cmd [OPT] command to encrypt passwords on disk
decrypt_cmd [OPT] command to decrypt saved passwords
ACCOUNT_CONFIG_KEY:
user [REQ] IMAP username, usually the full email address
password [REQ] password, stored with optional encrypt_cmd
server [REQ] IMAP server, e.g.: "imap.gmail.com"
port [REQ] IMAP server port
smtp_server [OPT] SMTP server, e.g.: "smtp.gmail.com"
smtp_port [OPT] SMTP server port
ssl [OPT] set to false to forcibly disable security
inbox [OPT] primary IMAP folder name (default="INBOX")
sent [OPT] IMAP folder name to use for sent mail, e.g.:"Sent"
folders [OPT] extra IMAP folders to fetch (sep=":")
the FOLDER_NAME used as the dir on the filesystem
has non-alphanumeric substrings replaced with _s
and all leading and trailing _s removed
e.g.:
email.Z.folders = junk:[GMail]/Drafts:_12_/ponies
=> ["junk", "gmail_drafts", "12_ponies"]
count_include [OPT] FOLDER_NAMEs for counts (default="inbox", sep=":")
list of FOLDER_NAMEs for account-wide unread/total counts
this controls what gets written to the global unread file,
and what is returned by --accounts
note this is the FOLDER_NAME, and not the IMAP folder
e.g.:
email.Z.sent = [GMail]/Sent Mail
email.Z.folders = [GMail]/Spam:[GMail]/Drafts
email.Z.count_include = inbox:gmail_spam:sent
=> included: INBOX, [GMail]/Spam, [GMail]/Sent Mail
excluded: [GMail]/Drafts
skip [OPT] set to true to skip during --update
body_cache_mode [OPT] one of [unread|all|none] (default="unread")
controls which bodies get cached during --update
(note: only caches the first MAX_BODIES_TO_CACHE=100)
unread: cache unread bodies (up to 100)
all: cache all bodies (up to 100)
none: do not cache bodies during --update
prefer_html [OPT] prefer html over plaintext (default="false")
new_unread_cmd [OPT] custom alert command
update_interval [OPT] GUI: seconds between account updates
refresh_interval [OPT] GUI: seconds between account refresh
filters [OPT] GUI: list of filter-buttons, e.g.:"s1=%a% s2=%b%"
each filter is separated by a space, and takes the form:
<FILTER_NAME>=%<FILTER_STRING>%
FILTER_NAME: the text of the button in the GUI
FILTER_STRING: query for /opt/qtemail/bin/email-search.pl
e.g.:
email.Z.filters = mary=%from~"mary sue"% ok=%body!~viagra%
=> ["mary", "ok"]
/opt/qtemail/bin/email.pl -h|--help
show this message
/opt/qtemail/bin/email.pl [--update] [--folder=FOLDER_NAME_FILTER] [ACCOUNT_NAME ACCOUNT_NAME ...]
-for each account specified {or all non-skipped accounts if none are specified}:
-login to IMAP server, or create file ~/.cache/email/ACCOUNT_NAME/error
-for each FOLDER_NAME {or just FOLDER_NAME_FILTER if specified}:
-fetch and write all message UIDs to
~/.cache/email/ACCOUNT_NAME/FOLDER_NAME/all
-fetch and cache all message headers in
~/.cache/email/ACCOUNT_NAME/FOLDER_NAME/headers/UID
-fetch and cache bodies according to body_cache_mode config
all => every header that was cached gets its body cached
unread => every unread message gets its body cached
none => no bodies are cached
~/.cache/email/ACCOUNT_NAME/FOLDER_NAME/bodies/UID
-fetch all unread messages and write their UIDs to
~/.cache/email/ACCOUNT_NAME/FOLDER_NAME/unread
-write all message UIDs that are now in unread and were not before
~/.cache/email/ACCOUNT_NAME/FOLDER_NAME/new-unread
-run /opt/qtemail/bin/email-search.pl --updatedb ACCOUNT_NAME FOLDER_NAME 100
-update global unread counts file ~/.cache/email/unread-counts
count the unread emails for each account in the folders in count_include
the default is just to include the counts for "inbox"
write the unread counts, one line per account, to ~/.cache/email/unread-counts
e.g.: 3:AOL
6:GMAIL
0:WORK_GMAIL
/opt/qtemail/bin/email.pl --smtp ACCOUNT_NAME SUBJECT BODY TO [ARG ARG ..]
simple wrapper around smtp-cli. {you can add extra recipients with --to}
calls:
/opt/qtemail/bin/smtp-cli \
--server=<smtp_server> --port=<smtp_port> \
--user=<user> --pass=<password> \
--from=<user> \
--subject=SUBJECT --body-plain=BODY \
--to=TO \
ARG ARG ..
/opt/qtemail/bin/email.pl --mark-read [--folder=FOLDER_NAME] ACCOUNT_NAME UID [UID UID ...]
login and mark the indicated message(s) as read
/opt/qtemail/bin/email.pl --mark-unread [--folder=FOLDER_NAME] ACCOUNT_NAME UID [UID UID ...]
login mark the indicated message(s) as unread
/opt/qtemail/bin/email.pl --delete [--folder=FOLDER_NAME] ACCOUNT_NAME UID [UID UID ...]
delete the indicated messages (from IMAP server AND local cache)
/opt/qtemail/bin/email.pl --delete-local [--folder=FOLDER_NAME] ACCOUNT_NAME UID [UID UID ...]
delete the indicated messages from the local cache ONLY
(does not delete from IMAP server)
/opt/qtemail/bin/email.pl --move [--folder=FOLDER_NAME] ACCOUNT_NAME DEST_FOLDER_NAME UID [UID UID ...]
move the indicated messages on the IMAP server from FOLDER_NAME to DEST_FOLDER_NAME
this deletes the indicated messages from the local cache.
this does NOT, however, download the newly moved messages in DEST_FOLDER_NAME;
you need to update DEST_FOLDER_NAME to fetch them from the IMAP server
/opt/qtemail/bin/email.pl --accounts
format and print information about each account
"ACCOUNT_NAME:<timestamp>:<relative_time>:<update_interval>s:<unread_count>/<total_count>:<error>"
/opt/qtemail/bin/email.pl --folders ACCOUNT_NAME
format and print information about each folder for the given account
"FOLDER_NAME:<unread_count>/<total_count>"
/opt/qtemail/bin/email.pl --header [--folder=FOLDER_NAME] ACCOUNT_NAME UID [UID UID ...]
format and print the header of the indicated message(s)
prints each of [Date Subject From To CC BCC]
one per line, formatted "UID.FIELD: VALUE"
/opt/qtemail/bin/email.pl --body [--no-download] [-0] [--folder=FOLDER_NAME] ACCOUNT_NAME UID [UID UID ...]
download, format and print the body of the indicated message(s)
if -0 is specified, print a NUL character after each body instead of a newline
if body is cached, skip download
if body is not cached and --no-download is specified, use empty string for body
instead of downloading the body
if message has a plaintext and HTML component, only one is returned
if prefer_html is true, HTML is returned, otherwise, plaintext
/opt/qtemail/bin/email.pl --body-plain [--no-download] [-0] [--folder=FOLDER_NAME] ACCOUNT_NAME UID [UID UID ...]
same as --body, but override prefer_html=false,
and attempt to convert the result to plaintext if it appears to be HTML
(uses /usr/bin/html2text if available, or just strips out the tags)
/opt/qtemail/bin/email.pl --body-html [--no-download] [-0] [--folder=FOLDER_NAME] ACCOUNT_NAME UID [UID UID ...]
same as --body, but override prefer_html=true
/opt/qtemail/bin/email.pl --attachments [--folder=FOLDER_NAME] ACCOUNT_NAME DEST_DIR UID [UID UID ...]
download the body of the indicated message(s) and save any attachments to DEST_DIR
if body is cached, skip download
/opt/qtemail/bin/email.pl --cache-all-bodies ACCOUNT_NAME FOLDER_NAME
attempt to download the body of all uncached bodies
/opt/qtemail/bin/email.pl --print [--folder=FOLDER_NAME] [ACCOUNT_NAME ACCOUNT_NAME ...]
format and print cached unread message headers and bodies
fetches bodies like "/opt/qtemail/bin/email.pl --body-plain --no-download",
similarly converting HTML to plaintext
formats whitespace in bodies, compressing multiple empty lines to a max of 2,
and prepending every line with 2 spaces
/opt/qtemail/bin/email.pl --summary [--folder=FOLDER_NAME] [ACCOUNT_NAME ACCOUNT_NAME ...]
format and print cached unread message headers
/opt/qtemail/bin/email.pl --status-line [ACCOUNT_NAME ACCOUNT_NAME ...]
{cached in ~/.cache/email/status-line when ~/.cache/email/unread-counts or error files change}
does not fetch anything, merely reads ~/.cache/email/unread-counts
format and print ~/.cache/email/unread-counts
the string is a space-separated list of the first character of
each account name followed by the integer count
no newline character is printed
if the count is zero for a given account, it is omitted
if accounts are specified, all but those are omitted
e.g.: A3 G6
/opt/qtemail/bin/email.pl --status-short [ACCOUNT_NAME ACCOUNT_NAME ...]
{cached in ~/.cache/email/status-short when ~/.cache/email/unread-counts or error files change}
does not fetch anything, merely reads ~/.cache/email/unread-counts
format and print ~/.cache/email/unread-counts
if accounts are specified, all but those are omitted
omits accounts with unread-count of 0
the string is two lines, each always containing exactly three characters
no line can be longer than 3, and if it is shorter, it is left-padded with spaces
each line ends in a newline character
if any account has error, prints:
"ERR", "<total>"
if any account has more then 99 emails, prints
"big", "<total>"
if more than two accounts have a positive unread-count, prints:
"all", "<total>"
if exactly two accounts have a positive unread-count, prints:
"<acc><count>", "<acc><count>"
if exactly one account has a positive unread-count, prints:
"<acc><count>", ""
otherwise, prints:
"", ""
<total> = total of all unread counts if less than 1000, or '!!!' otherwise
<acc> = first character of a given account name
<count> = unread count for the indicated account
/opt/qtemail/bin/email.pl --has-error [ACCOUNT_NAME ACCOUNT_NAME ...]
checks if ~/.cache/email/ACCOUNT_NAME/error exists
print "yes" and exit with zero exit code if it does
otherwise, print "no" and exit with non-zero exit code
/opt/qtemail/bin/email.pl --has-new-unread [ACCOUNT_NAME ACCOUNT_NAME ...]
checks for any NEW unread emails, in any account
{UIDs in ~/.cache/email/ACCOUNT_NAME/new-unread}
if accounts are specified, all but those are ignored
print "yes" and exit with zero exit code if there are new unread emails
otherwise, print "no" and exit with non-zero exit code
/opt/qtemail/bin/email.pl --has-unread [ACCOUNT_NAME ACCOUNT_NAME ...]
checks for any unread emails, in any account
{UIDs in ~/.cache/email/ACCOUNT_NAME/unread}
if accounts are specified, all but those are ignored
print "yes" and exit with zero exit code if there are unread emails
otherwise, print "no" and exit with non-zero exit code
/opt/qtemail/bin/email.pl --read-config ACCOUNT_NAME
reads ~/.secrets
for each line of the form "email.ACCOUNT_NAME.KEY\s*=\s*VAL"
print KEY=VAL
/opt/qtemail/bin/email.pl --write-config ACCOUNT_NAME KEY=VAL [KEY=VAL KEY=VAL]
modifies ~/.secrets
for each KEY/VAL pair:
removes any line that matches "email.ACCOUNT_NAME.KEY\s*="
adds a line at the end "email.ACCOUNT_NAME.KEY = VAL"
/opt/qtemail/bin/email.pl --read-options
reads ~/.secrets
for each line of the form "email.KEY\s*=\s*VAL"
print KEY=VAL
/opt/qtemail/bin/email.pl --write-options KEY=VAL [KEY=VAL KEY=VAL]
reads ~/.secrets
for each line of the form "email.KEY\s*=\s*VAL"
print KEY=VAL
/opt/qtemail/bin/email.pl --read-config-schema
print the allowed keys and descriptions for account config entries
formatted, one per line, like this:
<KEY_NAME>=<DESC>
KEY_NAME: one of: user password server port smtp_server smtp_port ssl inbox sent folders count_include skip body_cache_mode prefer_html new_unread_cmd update_interval refresh_interval filters
DESC: text description
/opt/qtemail/bin/email.pl --read-options-schema
print the allowed keys and descriptions for global option entries
formatted, one per line, like this:
<KEY_NAME>=<DESC>
KEY_NAME: one of: update_cmd encrypt_cmd decrypt_cmd
DESC: text description
===== email-search.pl =====
/opt/qtemail/bin/email-search.pl --updatedb ACCOUNT_NAME FOLDER_NAME LIMIT
create sqlite database if it doesnt exist
updates database incrementally
LIMIT
maximum number of headers to update at once
can be 'all' or a positive integer
/opt/qtemail/bin/email-search.pl --format WORD [WORD WORD..]
parse and format QUERY="WORD WORD WORD" for testing
/opt/qtemail/bin/email-search.pl --search [OPTIONS] ACCOUNT_NAME WORD [WORD WORD..]
print UIDs of emails matching QUERY="WORD WORD WORD .."
OPTIONS:
--folder=FOLDER_NAME
use FOLDER_NAME instead of "inbox"
--minuid=MIN_UID
ignore all UIDs below MIN_UID
--maxuid=MAX_UID
ignore all UIDs above MAX_UID
--limit=UID_LIMIT
ignore all except the last UID_LIMIT UIDs
SEARCH FORMAT:
-all words separated by spaces must match one of subject/date/from/to/cc/bcc
apple banana
=> emails where subject/from/to/cc/bcc/date matches both 'apple' AND 'banana'
-specify an individual field of subject/date/from/to/cc/bcc with a '~'
from~mary
=> emails from 'mary'
-negate a header field query with '!~' instead of '~'
from!~mary
=> emails from everyone EXCEPT 'mary'
-specify that the body must match with a '~'
body~bus
(can be abbreviated with just 'b', e.g.: "b~bus")
=> emails where the cached body matches 'bus'
-negate a body query with '!~' instead of '~'
body!~bus
=> emails where the cached body does NOT match 'bus'
-specify disjunction with '++'
from~mary ++ from~john ++ from~sue
=> emails from 'mary' PLUS emails from 'john' PLUS emails from 'sue'
-group space or ++ separated words with parentheses
(from~mary a) ++ (from~john b)
=> emails from 'mary' that match 'a' PLUS emails from 'john' that match 'b'
-parentheses can nest arbitrarily deep
(a ++ (b (c ++ d)))
=> emails that match 'a', PLUS emails that match 'b' AND match 'c' or 'd'
-special characters can be escaped with backslash
subject\~fish\ table
=> emails where subject/from/to/cc/bcc/date matches 'subject~fish table'
-doublequoted strings are treated as words
"this is a (single ++ w~ord)"
=> emails where subject/from/to/cc/bcc/date matches 'this is a (single ++ w~ord)'
GRAMMAR:
QUERY = <LIST_AND>
| <LIST_OR>
| <HEADER_QUERY>
| <NEGATED_HEADER_QUERY>
| <SIMPLE_HEADER_QUERY>
| <BODY_QUERY>
| <NEGATED_BODY_QUERY>
| (<QUERY>)
return emails that match this QUERY
LIST_AND = <QUERY> <QUERY>
return only emails that match both QUERYs
LIST_OR = <QUERY> ++ <QUERY>
return emails that match either QUERY or both
HEADER_QUERY = <HEADER_FIELD>~<PATTERN>
return emails where the indicated header field matches the pattern
NEGATED_HEADER_QUERY = <HEADER_FIELD>!~<PATTERN>
return emails where the indicated header field does NOT match the pattern
SIMPLE_HEADER_QUERY = <PATTERN>
return emails with at least one header field that matches the pattern
BODY_QUERY = body~<PATTERN>
return emails where the body matches the pattern
NEGATED_BODY_QUERY = body!~<PATTERN>
return emails where the body does NOT match the pattern
HEADER_FIELD = subject | from | to | cc | bcc | date | body
restricts the fields that PATTERN can match
PATTERN = <string> | <string>"<string>"<string>
can be any string, supports doublequote quoting and backslash escaping
EXAMPLES:
=====
from~mary
[from] LIKE mary
=====
mary smith
ALL(
|--[to cc bcc from subject] LIKE mary
|--[to cc bcc from subject] LIKE smith
)
=====
((a b) ++ (c d) ++ (e f))
ANY(
|--ALL(
| |--[to cc bcc from subject] LIKE a
| |--[to cc bcc from subject] LIKE b
| )
|--ALL(
| |--[to cc bcc from subject] LIKE c
| |--[to cc bcc from subject] LIKE d
| )
|--ALL(
| |--[to cc bcc from subject] LIKE e
| |--[to cc bcc from subject] LIKE f
| )
)
=====
subject~b ++ "subject~b"
ANY(
|--[subject] LIKE b
|--[to cc bcc from subject] LIKE subject~b
)
=====
from!~bob ++ subject!~math
ANY(
|--[from] NOT LIKE bob
|--[subject] NOT LIKE math
)
=====
"a ++ b"
[to cc bcc from subject] LIKE a ++ b
=====
===== email-gui.py =====
/opt/qtemail/bin/email-gui.py [OPTS]
OPTS:
--page=[account|header|config|send|folder|body]
start on the indicated page
--account=ACCOUNT_NAME
default the account to ACCOUNT_NAME {only useful with --page}
--folder=FOLDER_NAME
default the folder to ACCOUNT_NAME {only useful with --page}
--uid=UID
default the message to UID {only useful with --page}
About
No description, website, or topics provided.
Resources
Stars
Watchers
Forks
Packages 0
No packages published