twmail 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -0
- data/CONTRIBUTING.markdown +7 -0
- data/Gemfile +3 -2
- data/README.md +10 -16
- data/TODO.markdown +4 -0
- data/bin/task-uuid +4 -4
- data/bin/twmail +0 -1
- data/lib/twmail/version.rb +1 -1
- data/test/unit/test_task_uuid.rb +5 -5
- data/twmail.gemspec +2 -2
- metadata +18 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f8387ff67c2e8b5ee9b4061dfa36dddddd26e9b
|
4
|
+
data.tar.gz: 886975f525e024cba8d9d8ec86a55eec4880c70b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d7236e1a61c4addf575f3625a3195a16fefd2fdbe24baa66d341613fc00d46e52c8a119aea257e1a9a37bd8800174f258debf72eb1c48da14e828298bbdcb849
|
7
|
+
data.tar.gz: 507d2712dc34bdbe418f61b8eeb4d0d69bb28feb75ed05dfe2453add66710b5fac60f652d9d5ffb94984d18fa25f7553beb24ecf353b6ef6463c3d9e1703eb56
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.4.1
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -13,6 +13,7 @@
|
|
13
13
|
1. Edit `~/.fetchmailrc` and adjust mail account settings (the example was made for Google Mail account). If in doubt, consult the `fetchmail` documentation, e.g. by executing `man fetchmailconf` in a terminal.
|
14
14
|
|
15
15
|
## Motivation
|
16
|
+
|
16
17
|
I would like to add new tasks to my TaskWarrior inbox from remote places where I don't have immediate access to my personal TaskWarrior database; e.g. from my iPhone, from work (where I don't have access to my personal TaskWarrior installation) or from another computer.
|
17
18
|
|
18
19
|
Using eMail for this looks like a great candidate:
|
@@ -24,6 +25,7 @@ Using eMail for this looks like a great candidate:
|
|
24
25
|
What is missing from a TaskWarrior perspective right now is a way to add these mails to a TaskWarrior installation automatically.
|
25
26
|
|
26
27
|
## Architecture
|
28
|
+
|
27
29
|
The simplest solution I could come up with is this:
|
28
30
|
|
29
31
|
1. A dedicated email account is used to collect the tasks.
|
@@ -43,25 +45,24 @@ As a prerequisite, TaskWarrior is assumed to be installed and configured. With t
|
|
43
45
|
|
44
46
|
The solution presented here maintains a one-to-one relation between the INBOX of an mail account and the TaskWarrior database.
|
45
47
|
|
46
|
-
TODO Describe how to use fetchmail's daemon mode
|
47
|
-
|
48
|
-
TODO Describe how to use fetchmail's IMAP IDLE flag
|
49
|
-
|
50
48
|
## Components
|
49
|
+
|
51
50
|
Mail fetching is done with `fetchmail`, a proven solution available on all major Unices incl. MacOS. It will be configured to use the `twmail` script as a mail delivery agent (mda), which means nothing more than that `fetchmail` fetches the mail from the configured account and hands it over to our script. There is no further storage of the received mails except in TaskWarrior.
|
52
51
|
|
53
52
|
## Error Handling
|
54
|
-
If our MDA returns non-zero, `fetchmail` will not assume the message to be processed and it will try again.
|
55
53
|
|
56
|
-
|
54
|
+
If our MDA returns non-zero, `fetchmail` will not assume the message to be processed and it will try again.
|
57
55
|
|
58
56
|
## Alternatives
|
57
|
+
|
59
58
|
One might think of more elaborate applications that do more clever things, but I wanted to create this solution with as few external dependencies as possible. `fetchmail` is available on all Unices, and who can afford to live without TaskWarrior anyway? I also played with the thought of a central tasks server that receives mail from services like CloudMailIn and auto-adds them to the server, but the result would not be much different (besides being more complex) to the solution presented here: No task will be fetched into TaskWarrior until the machine with the TaskWarrior database is online.
|
60
59
|
|
61
60
|
Another alternative would be to convert the email to JSON and use TaskWarrior's import command. This would allow to create and annotate a new task in one step without the `bin/task-uuid` workaround.
|
62
61
|
|
63
62
|
## Advanced Usage
|
63
|
+
|
64
64
|
### Filtering and Routing
|
65
|
+
|
65
66
|
Many more advanced use cases like filtering and routing can be implemented on the mail server side. There are plenty of user interfaces for routing eMails based on their subject, sender, body text, etc. The simplest way to integrate these features with `twmail` is to use IMAP folders. After all filtering and routing, each eMail must end up in a dedicated IMAP folder (by default, all tasks are fetched from the INBOX folder). `twmail` can then be configured to do different things depending on which IMAP folder a mail came from.
|
66
67
|
|
67
68
|
As an example, here is a simple way to route eMails to different projects in TaskWarrior, based on their subject line:
|
@@ -73,11 +74,10 @@ As an example, here is a simple way to route eMails to different projects in Tas
|
|
73
74
|
1. "Get Rich Fast" folder if the mail subject contains "project:GetRichFast"
|
74
75
|
1. Tell `twmail` to fetch mails from the "Build Bikeshed", "Reading List", and "Get Rich Fast" IMAP folders (in addition to the INBOX):
|
75
76
|
|
76
|
-
TODO Continue description ... may need tracepolls for it.
|
77
|
-
|
78
77
|
The approach chosen for `twmail` also addresses SPAM filtering. Handling that remains the responsibility of the mail server. Anything that makes it to the INBOX is treated as task.
|
79
78
|
|
80
79
|
### Hooks
|
80
|
+
|
81
81
|
`twmail` comes with an advanced implementation that supports hooks. This makes handling incoming mail very simple for someone familiar with shell scripting, and there is no need to edit the `twmail` scripts in order to customize its behavior.
|
82
82
|
|
83
83
|
When `fetchmail` is configured to use `twmail-hook` instead of `twmail`, the script will call the `twmail-hook` command (must be in the user's `$PATH`). Within the hook script, the fields of the parsed email are available as environment variables:
|
@@ -96,6 +96,7 @@ If you prefer a hook with a different name, specify it in the `TWMAIL_HOOK` envi
|
|
96
96
|
mda TWMAIL_HOOK=~/taskwarrior-import.sh twmail-hook
|
97
97
|
|
98
98
|
## Housekeeping
|
99
|
+
|
99
100
|
By default `fetchmail` will mark retrieved messages as read, but leave them on the server. For housekeeping purposes, it may be desirable to delete messages from the server once they were successfully imported into TaskWarrior.
|
100
101
|
|
101
102
|
There are two ways to achieve this:
|
@@ -106,12 +107,5 @@ There are two ways to achieve this:
|
|
106
107
|
Which option to choose depends on the capabilities of your mail server (Google Mail cannot handle mails based on their read status), and on your level of trust in `twmail`. I recommend leaving mails on the server until you are confident that everything works as expected.
|
107
108
|
|
108
109
|
## Testing
|
109
|
-
`twmail` comes with a basic set of tests. Execute them by running `rake` in the cloned source repo.
|
110
110
|
|
111
|
-
|
112
|
-
|
113
|
-
1. Fork it
|
114
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
115
|
-
3. Commit your changes (`git commit -am 'Added some feature'`)
|
116
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
117
|
-
5. Create new Pull Request
|
111
|
+
`twmail` comes with a basic set of tests. Execute them by running `rake` in the cloned source repo.
|
data/TODO.markdown
ADDED
@@ -0,0 +1,4 @@
|
|
1
|
+
* Describe how to use fetchmail's daemon mode
|
2
|
+
* Describe how to use fetchmail's IMAP IDLE flag
|
3
|
+
* Do we need a dedicated dead-letter queue for all mails fetched, but not successfully processed?
|
4
|
+
* Consider the [gmail gem](https://github.com/gmailgem/gmail) instead of fetchmail
|
data/bin/task-uuid
CHANGED
@@ -17,22 +17,22 @@ OptionParser.new do |opts|
|
|
17
17
|
|
18
18
|
5. Print the UUID to STDOUT
|
19
19
|
HERE
|
20
|
-
opts.banner = banner
|
20
|
+
opts.banner = banner
|
21
21
|
opts.version = TaskWarriorMail::VERSION
|
22
22
|
end.parse!
|
23
23
|
|
24
24
|
# 1. Make a temporary tag that unlikely to exist yet.
|
25
25
|
# To avoid shell troubles, we have it start with a character.
|
26
|
-
tag =
|
26
|
+
tag = 'tag_' + SecureRandom.hex.tr('-', '')
|
27
27
|
|
28
28
|
# 2. Create the new task tagged with our temporary tag
|
29
29
|
%x|task rc.verbose=nothing add +#{tag} #{ARGV.join(' ')}|
|
30
30
|
|
31
31
|
# 3. Remember the UUID generated by TaskWarrior
|
32
|
-
task_uuid = %x|task
|
32
|
+
task_uuid = %x|task rc.verbose=nothing +#{tag} _uuid|.chomp
|
33
33
|
|
34
34
|
# 4. Remove the temporary tag from the new task
|
35
|
-
%x|task rc.verbose=nothing
|
35
|
+
%x|task rc.verbose=nothing #{task_uuid} modify -#{tag.to_s}|
|
36
36
|
|
37
37
|
# 5. Print the UUID to STDOUT
|
38
38
|
puts task_uuid
|
data/bin/twmail
CHANGED
data/lib/twmail/version.rb
CHANGED
data/test/unit/test_task_uuid.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'shellwords'
|
1
2
|
require 'open3'
|
2
3
|
require 'test/unit'
|
3
4
|
|
@@ -54,7 +55,7 @@ class TaskWarriorCommand < Command
|
|
54
55
|
end
|
55
56
|
|
56
57
|
def default_args
|
57
|
-
{'rc.verbose' => '
|
58
|
+
{'rc.verbose' => 'nothing', 'rc.json.array' => 'on'}
|
58
59
|
end
|
59
60
|
|
60
61
|
def executable
|
@@ -80,13 +81,12 @@ class TaskUUID < TaskWarriorCommand
|
|
80
81
|
end
|
81
82
|
end
|
82
83
|
|
83
|
-
class TestTaskUUID < Test::Unit::TestCase
|
84
|
+
class TestTaskUUID < Test::Unit::TestCase
|
84
85
|
def setup
|
85
86
|
@tw = TaskWarriorCommand.new
|
86
87
|
@tw.data_dir = Dir.mktmpdir(name)
|
87
88
|
|
88
89
|
raise "TASKRC must not be set, but it is #{ENV['TASKRC']}" if ENV['TASKRC']
|
89
|
-
|
90
90
|
end
|
91
91
|
|
92
92
|
def teardown
|
@@ -98,7 +98,7 @@ class TestTaskUUID < Test::Unit::TestCase#Minitest::Test
|
|
98
98
|
assert(status.success?)
|
99
99
|
assert_empty(err)
|
100
100
|
assert_not_empty(out)
|
101
|
-
|
101
|
+
assert_match(/\d\.\d\.\d/, out.chomp)
|
102
102
|
end
|
103
103
|
|
104
104
|
def test_empty
|
@@ -112,7 +112,7 @@ class TestTaskUUID < Test::Unit::TestCase#Minitest::Test
|
|
112
112
|
def test_task_uuid
|
113
113
|
task_uuid = TaskUUID.new
|
114
114
|
task_uuid.data_dir = Dir.mktmpdir(name)
|
115
|
-
out, err,
|
115
|
+
out, err, _ = task_uuid.create('foo bar')
|
116
116
|
assert_empty(err)
|
117
117
|
assert_not_empty(out)
|
118
118
|
assert_match(/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/, out.chomp)
|
data/twmail.gemspec
CHANGED
@@ -15,11 +15,11 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = TaskWarriorMail::VERSION
|
17
17
|
|
18
|
-
gem.add_dependency 'twtest'
|
19
18
|
gem.add_dependency 'mail'
|
20
|
-
gem.add_dependency 'multi_json'
|
21
19
|
|
20
|
+
gem.add_development_dependency 'twtest', '> 0.0.6'
|
22
21
|
gem.add_development_dependency 'guard-test'
|
23
22
|
gem.add_development_dependency 'guard-bundler'
|
24
23
|
gem.add_development_dependency 'pry'
|
24
|
+
gem.add_development_dependency 'rake'
|
25
25
|
end
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twmail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nicholas E. Rabenau
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-06-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: mail
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -25,27 +25,27 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: twtest
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
34
|
-
type: :
|
33
|
+
version: 0.0.6
|
34
|
+
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 0.0.6
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: guard-test
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
|
-
type: :
|
48
|
+
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
@@ -53,7 +53,7 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name: guard-
|
56
|
+
name: guard-bundler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
@@ -67,7 +67,7 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: pry
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
@@ -81,7 +81,7 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: rake
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
@@ -105,11 +105,14 @@ extensions: []
|
|
105
105
|
extra_rdoc_files: []
|
106
106
|
files:
|
107
107
|
- ".gitignore"
|
108
|
+
- ".ruby-version"
|
109
|
+
- CONTRIBUTING.markdown
|
108
110
|
- Gemfile
|
109
111
|
- Guardfile
|
110
112
|
- LICENSE
|
111
113
|
- README.md
|
112
114
|
- Rakefile
|
115
|
+
- TODO.markdown
|
113
116
|
- bin/task-uuid
|
114
117
|
- bin/twmail
|
115
118
|
- bin/twmail-hook
|
@@ -151,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
151
154
|
version: '0'
|
152
155
|
requirements: []
|
153
156
|
rubyforge_project:
|
154
|
-
rubygems_version: 2.
|
157
|
+
rubygems_version: 2.6.11
|
155
158
|
signing_key:
|
156
159
|
specification_version: 4
|
157
160
|
summary: Use fetchmail and the scripts in this project to mail tasks to your local
|