imap-backup 0.0.5 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +43 -6
- data/bin/imap-backup +0 -1
- data/imap-backup.gemspec +1 -1
- data/lib/email/mboxrd/message.rb +37 -0
- data/lib/imap/backup.rb +2 -0
- data/lib/imap/backup/account/connection.rb +2 -4
- data/lib/imap/backup/account/folder.rb +0 -2
- data/lib/imap/backup/configuration/account.rb +0 -2
- data/lib/imap/backup/configuration/asker.rb +0 -2
- data/lib/imap/backup/configuration/folder_chooser.rb +0 -2
- data/lib/imap/backup/configuration/list.rb +17 -16
- data/lib/imap/backup/configuration/setup.rb +1 -3
- data/lib/imap/backup/configuration/store.rb +19 -13
- data/lib/imap/backup/downloader.rb +0 -2
- data/lib/imap/backup/serializer/base.rb +17 -0
- data/lib/imap/backup/serializer/directory.rb +3 -7
- data/lib/imap/backup/serializer/mbox.rb +96 -0
- data/lib/imap/backup/utils.rb +6 -3
- data/lib/imap/backup/version.rb +2 -2
- data/spec/unit/account/connection_spec.rb +12 -13
- data/spec/unit/account/folder_spec.rb +1 -9
- data/spec/unit/configuration/account_spec.rb +1 -16
- data/spec/unit/configuration/asker_spec.rb +1 -9
- data/spec/unit/configuration/connection_tester_spec.rb +1 -5
- data/spec/unit/configuration/folder_chooser_spec.rb +1 -7
- data/spec/unit/configuration/list_spec.rb +24 -20
- data/spec/unit/configuration/setup_spec.rb +3 -9
- data/spec/unit/configuration/store_spec.rb +11 -20
- data/spec/unit/downloader_spec.rb +1 -11
- data/spec/unit/email/mboxrd/message_spec.rb +51 -0
- data/spec/unit/serializer/base_spec.rb +19 -0
- data/spec/unit/serializer/directory_spec.rb +51 -74
- data/spec/unit/serializer/mbox_spec.rb +113 -0
- data/spec/unit/utils_spec.rb +3 -9
- metadata +29 -4
@@ -1,22 +1,18 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
2
|
+
require 'spec_helper'
|
3
3
|
|
4
4
|
describe Imap::Backup::Configuration::Setup do
|
5
|
-
|
6
5
|
include HighLineTestHelpers
|
7
6
|
|
8
7
|
context '#initialize' do
|
9
|
-
|
10
8
|
it 'should not require the config file to exist' do
|
11
|
-
Imap::Backup::Configuration::Store.should_receive(:new)
|
9
|
+
Imap::Backup::Configuration::Store.should_receive(:new)
|
12
10
|
|
13
11
|
Imap::Backup::Configuration::Setup.new
|
14
12
|
end
|
15
|
-
|
16
13
|
end
|
17
14
|
|
18
15
|
context '#run' do
|
19
|
-
|
20
16
|
before :each do
|
21
17
|
prepare_store
|
22
18
|
@input, @output = prepare_highline
|
@@ -26,7 +22,7 @@ describe Imap::Backup::Configuration::Setup do
|
|
26
22
|
@account1 = { :username => 'account@example.com' }
|
27
23
|
@data = { :accounts => [ @account1 ] }
|
28
24
|
@store = stub('Imap::Backup::Configuration::Store', :data => @data, :path => '/base/path')
|
29
|
-
Imap::Backup::Configuration::Store.stub!(:new).
|
25
|
+
Imap::Backup::Configuration::Store.stub!(:new).and_return(@store)
|
30
26
|
end
|
31
27
|
|
32
28
|
subject { Imap::Backup::Configuration::Setup.new }
|
@@ -109,8 +105,6 @@ describe Imap::Backup::Configuration::Setup do
|
|
109
105
|
|
110
106
|
subject.run
|
111
107
|
end
|
112
|
-
|
113
108
|
end
|
114
|
-
|
115
109
|
end
|
116
110
|
|
@@ -1,8 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
2
|
+
require 'spec_helper'
|
3
3
|
|
4
4
|
describe Imap::Backup::Configuration::Store do
|
5
|
-
|
6
5
|
before :all do
|
7
6
|
@configuration_directory = Imap::Backup::Configuration::Store::CONFIGURATION_DIRECTORY
|
8
7
|
Imap::Backup::Configuration::Store.instance_eval { remove_const :'CONFIGURATION_DIRECTORY' }
|
@@ -14,27 +13,25 @@ describe Imap::Backup::Configuration::Store do
|
|
14
13
|
Imap::Backup::Configuration::Store::CONFIGURATION_DIRECTORY = @configuration_directory
|
15
14
|
end
|
16
15
|
|
17
|
-
context '
|
16
|
+
context '.exist?' do
|
17
|
+
it 'checks if the file exists' do
|
18
|
+
File.should_receive(:exist?).with('/base/path/config.json').and_return(true)
|
19
|
+
|
20
|
+
Imap::Backup::Configuration::Store.exist?
|
21
|
+
end
|
22
|
+
end
|
18
23
|
|
24
|
+
context '#initialize' do
|
19
25
|
before :each do
|
20
26
|
Imap::Backup::Utils.stub!(:check_permissions => nil)
|
21
27
|
end
|
22
28
|
|
23
|
-
it '
|
29
|
+
it 'should not fail if the configuration file is missing' do
|
24
30
|
File.should_receive(:directory?).with('/base/path').and_return(true)
|
25
31
|
File.should_receive(:exist?).with('/base/path/config.json').and_return(false)
|
26
32
|
|
27
33
|
expect do
|
28
34
|
Imap::Backup::Configuration::Store.new
|
29
|
-
end.to raise_error(Imap::Backup::ConfigurationNotFound, /not found/)
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'should not fail if fail_if_missing is false' do
|
33
|
-
File.should_receive(:directory?).with('/base/path').and_return(true)
|
34
|
-
File.should_receive(:exist?).with('/base/path/config.json').and_return(false)
|
35
|
-
|
36
|
-
expect do
|
37
|
-
Imap::Backup::Configuration::Store.new(false)
|
38
35
|
end.to_not raise_error
|
39
36
|
end
|
40
37
|
|
@@ -57,11 +54,9 @@ describe Imap::Backup::Configuration::Store do
|
|
57
54
|
|
58
55
|
Imap::Backup::Configuration::Store.new
|
59
56
|
end
|
60
|
-
|
61
57
|
end
|
62
58
|
|
63
59
|
context '#save' do
|
64
|
-
|
65
60
|
before :each do
|
66
61
|
# initialize
|
67
62
|
File.stub!(:directory?).with('/base/path').and_return(false)
|
@@ -78,7 +73,7 @@ describe Imap::Backup::Configuration::Store do
|
|
78
73
|
FileUtils.stub!(:chmod).with(0600, '/base/path/config.json')
|
79
74
|
end
|
80
75
|
|
81
|
-
subject { Imap::Backup::Configuration::Store.new
|
76
|
+
subject { Imap::Backup::Configuration::Store.new }
|
82
77
|
|
83
78
|
it 'should create the config directory' do
|
84
79
|
File.should_receive(:directory?).with('/base/path').and_return(false)
|
@@ -100,7 +95,6 @@ describe Imap::Backup::Configuration::Store do
|
|
100
95
|
end
|
101
96
|
|
102
97
|
context 'saving accounts' do
|
103
|
-
|
104
98
|
before :each do
|
105
99
|
# initialize
|
106
100
|
File.stub!(:exist?).with('/base/path/config.json').and_return(true)
|
@@ -164,10 +158,7 @@ describe Imap::Backup::Configuration::Store do
|
|
164
158
|
|
165
159
|
subject.save
|
166
160
|
end
|
167
|
-
|
168
161
|
end
|
169
|
-
|
170
162
|
end
|
171
|
-
|
172
163
|
end
|
173
164
|
|
@@ -1,10 +1,8 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
2
|
+
require 'spec_helper'
|
3
3
|
|
4
4
|
describe Imap::Backup::Downloader do
|
5
|
-
|
6
5
|
context 'with account and downloader' do
|
7
|
-
|
8
6
|
before :each do
|
9
7
|
local_path = '/base/path'
|
10
8
|
stat = stub('File::Stat', :mode => 0700)
|
@@ -24,9 +22,7 @@ describe Imap::Backup::Downloader do
|
|
24
22
|
subject { Imap::Backup::Downloader.new(@folder, @serializer) }
|
25
23
|
|
26
24
|
context '#run' do
|
27
|
-
|
28
25
|
context 'with folder' do
|
29
|
-
|
30
26
|
it 'should list messages' do
|
31
27
|
@folder.should_receive(:uids).and_return([])
|
32
28
|
|
@@ -70,16 +66,10 @@ describe Imap::Backup::Downloader do
|
|
70
66
|
|
71
67
|
subject.run
|
72
68
|
end
|
73
|
-
|
74
69
|
end
|
75
|
-
|
76
70
|
end
|
77
|
-
|
78
71
|
end
|
79
|
-
|
80
72
|
end
|
81
|
-
|
82
73
|
end
|
83
|
-
|
84
74
|
end
|
85
75
|
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Email::Mboxrd::Message do
|
6
|
+
let(:from) { 'me@example.com' }
|
7
|
+
let(:date) { DateTime.new(2012, 12, 13, 18, 23, 45) }
|
8
|
+
let(:message_body) { "Foo\nBar\nFrom at the beginning of the line\n>>From quoted" }
|
9
|
+
subject { Email::Mboxrd::Message.new(message_body) }
|
10
|
+
|
11
|
+
context '#to_s' do
|
12
|
+
let(:mail) do
|
13
|
+
mail = stub('Mail')
|
14
|
+
mail.stub(:from).and_return([from])
|
15
|
+
mail.stub(:date).and_return(date)
|
16
|
+
mail
|
17
|
+
end
|
18
|
+
|
19
|
+
before do
|
20
|
+
Mail.stub(:new).with(message_body).and_return(mail)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'does not modify the message' do
|
24
|
+
message_body2 = message_body.clone
|
25
|
+
|
26
|
+
message_body.should_receive(:clone).and_return(message_body2)
|
27
|
+
message_body.should_not_receive(:force_encoding).with('binary')
|
28
|
+
|
29
|
+
subject.to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'parses the message' do
|
33
|
+
Mail.should_receive(:new).with(message_body).and_return(mail)
|
34
|
+
|
35
|
+
subject.to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
it "adds a 'From ' line at the start" do
|
39
|
+
expect(subject.to_s).to start_with('From ' + from + ' ' + date.asctime + "\n")
|
40
|
+
end
|
41
|
+
|
42
|
+
it "replaces existing 'From ' with '>From '" do
|
43
|
+
expect(subject.to_s).to include("\n>From at the beginning")
|
44
|
+
end
|
45
|
+
|
46
|
+
it "appends > before '>+From '" do
|
47
|
+
expect(subject.to_s).to include("\n>>>From quoted")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Imap::Backup::Serializer::Base do
|
6
|
+
context '#initialize' do
|
7
|
+
let(:stat) { stub('File::Stat', :mode => 0345) }
|
8
|
+
|
9
|
+
it 'should fail if file permissions are to lax' do
|
10
|
+
File.stub!(:exist?).with('/base/path').and_return(true)
|
11
|
+
File.should_receive(:stat).with('/base/path').and_return(stat)
|
12
|
+
|
13
|
+
expect do
|
14
|
+
Imap::Backup::Serializer::Base.new('/base/path', 'my_folder')
|
15
|
+
end.to raise_error(RuntimeError, "Permissions on '/base/path' should be 0700, not 0345")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -1,102 +1,79 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
3
|
-
load File.expand_path('../../spec_helper.rb', File.dirname(__FILE__))
|
2
|
+
require 'spec_helper'
|
4
3
|
|
5
4
|
describe Imap::Backup::Serializer::Directory do
|
5
|
+
let(:stat) { stub('File::Stat', :mode => 0700) }
|
6
|
+
let(:files) { ['00000123.json', '000001.json'] }
|
7
|
+
|
8
|
+
before do
|
9
|
+
File.stub!(:stat).with('/base/path').and_return(stat)
|
10
|
+
FileUtils.stub!(:mkdir_p).with('/base/path/my_folder')
|
11
|
+
FileUtils.stub!(:chmod).with(0700, '/base/path/my_folder')
|
12
|
+
File.stub!(:exist?).with('/base/path').and_return(true)
|
13
|
+
end
|
6
14
|
|
7
|
-
|
15
|
+
subject { Imap::Backup::Serializer::Directory.new('/base/path', 'my_folder') }
|
8
16
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
17
|
+
context '#uids' do
|
18
|
+
it 'should return the backed-up uids' do
|
19
|
+
File.should_receive(:exist?).with('/base/path/my_folder').and_return(true)
|
20
|
+
Dir.should_receive(:open).with('/base/path/my_folder').and_return(files)
|
13
21
|
|
14
|
-
|
15
|
-
Imap::Backup::Serializer::Directory.new('/base/path', 'my_folder')
|
16
|
-
end.to raise_error(RuntimeError, "Permissions on '/base/path' should be 0700, not 0345")
|
22
|
+
subject.uids.should == [1, 123]
|
17
23
|
end
|
18
24
|
|
19
|
-
|
20
|
-
|
21
|
-
context 'with object' do
|
25
|
+
it 'should return an empty Array if the directory does not exist' do
|
26
|
+
File.should_receive(:exist?).with('/base/path/my_folder').and_return(false)
|
22
27
|
|
23
|
-
|
24
|
-
stat = stub('File::Stat', :mode => 0700)
|
25
|
-
File.stub!(:stat).with('/base/path').and_return(stat)
|
26
|
-
FileUtils.stub!(:mkdir_p).with('/base/path/my_folder')
|
27
|
-
FileUtils.stub!(:chmod).with(0700, '/base/path/my_folder')
|
28
|
-
File.stub!(:exist?).with('/base/path').and_return(true)
|
28
|
+
subject.uids.should == []
|
29
29
|
end
|
30
|
+
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
it 'should return the backed-up uids' do
|
36
|
-
files = ['00000123.json', '000001.json']
|
37
|
-
|
38
|
-
File.should_receive(:exist?).with('/base/path/my_folder').and_return(true)
|
39
|
-
Dir.should_receive(:open).with('/base/path/my_folder').and_return(files)
|
40
|
-
|
41
|
-
subject.uids.should == [1, 123]
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'should return an empty Array if the directory does not exist' do
|
45
|
-
File.should_receive(:exist?).with('/base/path/my_folder').and_return(false)
|
46
|
-
|
47
|
-
subject.uids.should == []
|
48
|
-
end
|
32
|
+
context '#exist?' do
|
33
|
+
it 'should check if the file exists' do
|
34
|
+
File.should_receive(:exist?).with(%r{/base/path/my_folder/0+123.json}).and_return(true)
|
49
35
|
|
36
|
+
subject.exist?(123).should be_true
|
50
37
|
end
|
38
|
+
end
|
51
39
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
40
|
+
context '#save' do
|
41
|
+
let(:message) do
|
42
|
+
{
|
43
|
+
'RFC822' => 'the body',
|
44
|
+
'other' => 'xxx'
|
45
|
+
}
|
46
|
+
end
|
47
|
+
let(:file) { stub('File', :write => nil) }
|
56
48
|
|
57
|
-
|
49
|
+
before do
|
50
|
+
File.stub!(:exist?).with(%r{/base/path/my_folder/0+1234.json}).and_return(true)
|
51
|
+
FileUtils.stub!(:chmod).with(0600, /0+1234.json$/)
|
52
|
+
File.stub!(:open) do |&block|
|
53
|
+
block.call file
|
58
54
|
end
|
59
|
-
|
60
55
|
end
|
61
56
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
File.stub!(:exist?).with(%r{/base/path/my_folder/0+1234.json}).and_return(true)
|
66
|
-
FileUtils.stub!(:chmod).with(0600, /0+1234.json$/)
|
67
|
-
@message = {
|
68
|
-
'RFC822' => 'the body',
|
69
|
-
'other' => 'xxx'
|
70
|
-
}
|
71
|
-
@file = stub('File', :write => nil)
|
72
|
-
File.stub!(:open) do |&block|
|
73
|
-
block.call @file
|
74
|
-
end
|
57
|
+
it 'should save messages' do
|
58
|
+
File.should_receive(:open) do |&block|
|
59
|
+
block.call file
|
75
60
|
end
|
61
|
+
file.should_receive(:write).with(/the body/)
|
76
62
|
|
77
|
-
|
78
|
-
|
79
|
-
block.call @file
|
80
|
-
end
|
81
|
-
@file.should_receive(:write).with(/the body/)
|
82
|
-
|
83
|
-
subject.save('1234', @message)
|
84
|
-
end
|
63
|
+
subject.save('1234', message)
|
64
|
+
end
|
85
65
|
|
86
|
-
|
87
|
-
|
66
|
+
it 'should JSON encode messages' do
|
67
|
+
message.should_receive(:to_json)
|
88
68
|
|
89
|
-
|
90
|
-
|
69
|
+
subject.save('1234', message)
|
70
|
+
end
|
91
71
|
|
92
|
-
|
93
|
-
|
72
|
+
it 'should set file permissions' do
|
73
|
+
FileUtils.should_receive(:chmod).with(0600, /0+1234.json$/)
|
94
74
|
|
95
|
-
|
96
|
-
end
|
75
|
+
subject.save(1234, message)
|
97
76
|
end
|
98
|
-
|
99
77
|
end
|
100
|
-
|
101
78
|
end
|
102
79
|
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Imap::Backup::Serializer::Mbox do
|
6
|
+
let(:stat) { stub('File::Stat', :mode => 0700) }
|
7
|
+
let(:mbox_pathname) { '/base/path/my/folder.mbox' }
|
8
|
+
let(:imap_pathname) { '/base/path/my/folder.imap' }
|
9
|
+
|
10
|
+
before do
|
11
|
+
File.stub(:exist?).with('/base/path').and_return(true)
|
12
|
+
File.stub!(:stat).with('/base/path').and_return(stat)
|
13
|
+
Imap::Backup::Utils.stub(:make_folder)
|
14
|
+
end
|
15
|
+
|
16
|
+
context '#initialize' do
|
17
|
+
before do
|
18
|
+
File.stub(:exist?).with(mbox_pathname).and_return(true)
|
19
|
+
File.stub(:exist?).with(imap_pathname).and_return(true)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'creates the containing directory' do
|
23
|
+
Imap::Backup::Utils.should_receive(:make_folder).with('/base/path', 'my', 0700)
|
24
|
+
|
25
|
+
Imap::Backup::Serializer::Mbox.new('/base/path', 'my/folder')
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'mbox and imap files' do
|
29
|
+
it 'checks if they exist' do
|
30
|
+
File.should_receive(:exist?).with(mbox_pathname).and_return(true)
|
31
|
+
File.should_receive(:exist?).with(imap_pathname).and_return(true)
|
32
|
+
|
33
|
+
Imap::Backup::Serializer::Mbox.new('/base/path', 'my/folder')
|
34
|
+
end
|
35
|
+
|
36
|
+
it "fails if mbox exists and imap doesn't" do
|
37
|
+
File.stub(:exist?).with(imap_pathname).and_return(false)
|
38
|
+
|
39
|
+
expect {
|
40
|
+
Imap::Backup::Serializer::Mbox.new('/base/path', 'my/folder')
|
41
|
+
}.to raise_error(RuntimeError, '.imap file missing')
|
42
|
+
end
|
43
|
+
|
44
|
+
it "fails if imap exists and mbox doesn't" do
|
45
|
+
File.stub(:exist?).with(mbox_pathname).and_return(false)
|
46
|
+
|
47
|
+
expect {
|
48
|
+
Imap::Backup::Serializer::Mbox.new('/base/path', 'my/folder')
|
49
|
+
}.to raise_error(RuntimeError, '.mbox file missing')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'instance methods' do
|
55
|
+
before do
|
56
|
+
File.stub(:exist?).with(mbox_pathname).and_return(true)
|
57
|
+
File.stub(:exist?).with(imap_pathname).and_return(true)
|
58
|
+
CSV.stub(:foreach) do |&block|
|
59
|
+
block.call ['1']
|
60
|
+
block.call ['123']
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
subject { Imap::Backup::Serializer::Mbox.new('/base/path', 'my/folder') }
|
65
|
+
|
66
|
+
context '#uids' do
|
67
|
+
it 'returns the backed-up uids' do
|
68
|
+
File.should_receive(:exist?).with(mbox_pathname).and_return(true)
|
69
|
+
File.should_receive(:exist?).with(imap_pathname).and_return(true)
|
70
|
+
|
71
|
+
expect(subject.uids).to eq(['1', '123'])
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'returns an empty Array if the mbox does not exist' do
|
75
|
+
File.stub(:exist?).with(mbox_pathname).and_return(false)
|
76
|
+
File.stub(:exist?).with(imap_pathname).and_return(false)
|
77
|
+
File.should_receive(:exist?).with(mbox_pathname).and_return(false)
|
78
|
+
File.should_receive(:exist?).with(imap_pathname).and_return(false)
|
79
|
+
|
80
|
+
expect(subject.uids).to eq([])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context '#save' do
|
85
|
+
let(:mbox_formatted_message) { 'message in mbox format' }
|
86
|
+
let(:message_uid) { '999' }
|
87
|
+
let(:message) { stub('Email::Mboxrd::Message', :to_s => mbox_formatted_message) }
|
88
|
+
let(:mbox_file) { stub('File - mbox', :close => nil) }
|
89
|
+
let(:imap_file) { stub('File - imap', :close => nil) }
|
90
|
+
|
91
|
+
before do
|
92
|
+
Email::Mboxrd::Message.stub(:new => message)
|
93
|
+
File.stub(:open).with(mbox_pathname, 'ab').and_return(mbox_file)
|
94
|
+
File.stub(:open).with(imap_pathname, 'ab').and_return(imap_file)
|
95
|
+
mbox_file.stub(:write).with(mbox_formatted_message)
|
96
|
+
imap_file.stub(:write).with(message_uid + "\n")
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'saves the message to the mbox' do
|
100
|
+
mbox_file.should_receive(:write).with(mbox_formatted_message)
|
101
|
+
|
102
|
+
subject.save(message_uid, "The\nemail\n")
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'saves the uid to the imap file' do
|
106
|
+
imap_file.should_receive(:write).with(message_uid + "\n")
|
107
|
+
|
108
|
+
subject.save(message_uid, "The\nemail\n")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|