chronicle-email 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e37ee5bdabd254e03a06962503f5875ab75d2aa0b271aff0b946c73f673d5cc3
4
- data.tar.gz: c351c35f1b5545f0d0f9e6b4375076b159dab88eb454cf3e946fdab84ddc03a4
3
+ metadata.gz: e0d66a6d2109f4f46f23fdf0c157085aed6f757f962339a422e4e38ca86ed129
4
+ data.tar.gz: e4136e05cf2827f64a07657e9442f9a8cdcac1ab88ed589c52ea76f62fd0d315
5
5
  SHA512:
6
- metadata.gz: fedb95cf29c21d0dac17d6cbeca81da0a5318ab41ea8a5eaf355e8996606b03398ba70c4233e4591a78ceaef5ce5242b59c5e227e79a6310ba4474c245476e57
7
- data.tar.gz: 7a06834ea16425d456da704b3272c96d6e0f427044e46e60a477dbce1cab7f9621056f4f18f7b90a964f83e3e85281a981fdf155155ebf4cb8b06871cd9884ab
6
+ metadata.gz: 5d58d42a6db25951b46a08ad44302dab836fc3063fae2b9074e5156b4db59ab147b8401b60860665a0a27394ddca98a48c58a6abdf87ce474439e4d7b179604f
7
+ data.tar.gz: b11bea8171510544c35742cb7ab72c162b7774d0bd5603a7453f065d270a230fa8b2a17d77d5bfc1205a60710f1b7d076ec4f6521630754006a5efe4e6b18fcc
data/.rubocop.yml ADDED
@@ -0,0 +1,2 @@
1
+ inherit_gem:
2
+ chronicle-core: .rubocop-plugin.yml
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in chronicle-email.gemspec
6
6
  gemspec
data/README.md CHANGED
@@ -21,11 +21,11 @@ $ chronicle-etl secrets:set imap username foo@gmail.com
21
21
  $ chronicle-etl secrets:set imap password APPPASSWORD
22
22
 
23
23
  # Then, retrieve your email from the last five days
24
- $ chronicle-etl --extractor email:imap --transformer email --since 5d --loader json
24
+ $ chronicle-etl --extractor email:imap --schema chronicle --since 5d
25
25
 
26
26
  # If you don't want to save your credentials as a secret, you can just pass
27
27
  # them to the extractor directly
28
- $ chronicle-etl --extractor email:imap --transformer email --since 5d --loader json \
28
+ $ chronicle-etl --extractor email:imap --schema chronicle --since 5d --loader json \
29
29
  --extractor-opts username:foo@gmail.com --password:APPPASSWORD
30
30
  ```
31
31
 
@@ -34,7 +34,7 @@ The MBOX format is used to archive an email mailbox. [Google Takeout](https://ta
34
34
 
35
35
  ```sh
36
36
  # Retrieve the subject lines of all emails in test.mbox
37
- $ chronicle-etl --extractor email:mbox --input inbox.mbox --transformer email --fields subject
37
+ $ chronicle-etl --extractor email:mbox --input ~/Downloads/inbox.mbox --fields subject
38
38
  ```
39
39
 
40
40
  ## Available Connectors
data/Rakefile CHANGED
@@ -1,6 +1,2 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
-
4
- RSpec::Core::RakeTask.new(:spec)
5
-
6
- task :default => :spec
1
+ require 'bundler/gem_tasks'
2
+ task default: %i[]
data/bin/console CHANGED
@@ -1,14 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "bundler/setup"
4
- require "chronicle/email"
3
+ require 'bundler/setup'
4
+ require 'chronicle/email'
5
5
 
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start(__FILE__)
6
+ require 'pry'
7
+ Pry.start
@@ -1,47 +1,54 @@
1
-
2
- lib = File.expand_path("../lib", __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "chronicle/email/version"
3
+ require 'chronicle/email/version'
5
4
 
6
5
  Gem::Specification.new do |spec|
7
- spec.name = "chronicle-email"
6
+ spec.name = 'chronicle-email'
8
7
  spec.version = Chronicle::Email::VERSION
9
- spec.authors = ["Andrew Louis"]
10
- spec.email = ["andrew@hyfen.net"]
8
+ spec.authors = ['Andrew Louis']
9
+ spec.email = ['andrew@hyfen.net']
11
10
 
12
- spec.summary = "Email importer for Chronicle"
13
- spec.description = "Various email importers for chronicle-etl"
14
- spec.homepage = "https://github.com/chronicle-app/chronicle-email"
15
- spec.license = "MIT"
11
+ spec.summary = 'Email importer for Chronicle'
12
+ spec.description = 'Various email importers for chronicle-etl'
13
+ spec.homepage = 'https://github.com/chronicle-app/chronicle-email'
14
+ spec.license = 'MIT'
16
15
 
17
16
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
17
  # to allow pushing to a single host or delete this section to allow pushing to any host.
19
18
  if spec.respond_to?(:metadata)
20
19
  # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
21
20
 
22
- spec.metadata["homepage_uri"] = spec.homepage
23
- spec.metadata["source_code_uri"] = "https://github.com/chronicle-app/chronicle-email"
24
- spec.metadata["changelog_uri"] = "https://github.com/chronicle-app/chronicle-email"
21
+ spec.metadata['homepage_uri'] = spec.homepage
22
+ spec.metadata['source_code_uri'] = 'https://github.com/chronicle-app/chronicle-email'
23
+ spec.metadata['changelog_uri'] = 'https://github.com/chronicle-app/chronicle-email'
25
24
  else
26
- raise "RubyGems 2.0 or newer is required to protect against " \
27
- "public gem pushes."
25
+ raise 'RubyGems 2.0 or newer is required to protect against ' \
26
+ 'public gem pushes.'
28
27
  end
29
28
 
30
29
  # Specify which files should be added to the gem when it is released.
31
30
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
32
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
31
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
33
32
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
34
33
  end
35
- spec.bindir = "exe"
34
+ spec.bindir = 'exe'
36
35
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
37
- spec.require_paths = ["lib"]
36
+ spec.require_paths = ['lib']
37
+ spec.metadata['rubygems_mfa_required'] = 'true'
38
+ spec.required_ruby_version = '>= 3.1'
38
39
 
39
- spec.add_dependency "chronicle-etl", "~> 0.5"
40
- spec.add_dependency "mail", "~> 2.7"
41
40
  spec.add_dependency 'email_reply_parser', '~> 0.5'
41
+ spec.add_dependency 'mail', '~> 2.7'
42
42
  spec.add_dependency 'reverse_markdown', '~> 2.0'
43
-
44
- spec.add_development_dependency "bundler", "~> 2.1"
45
- spec.add_development_dependency "rake", "~> 13.0"
46
- spec.add_development_dependency "rspec", "~> 3.9"
43
+ # Needed for Ruby 3.1 compatibility (https://github.com/mikel/mail/pull/1439#issuecomment-1002801221)
44
+ # TODO: check back for new version of `mail`
45
+ spec.add_dependency 'chronicle-core', '~> 0.3'
46
+ spec.add_dependency 'chronicle-etl', '~> 0.6'
47
+ spec.add_dependency 'net-imap'
48
+ spec.add_dependency 'net-smtp'
49
+
50
+ spec.add_development_dependency 'bundler', '~> 2.3'
51
+ spec.add_development_dependency 'pry-byebug', '~> 3.10'
52
+ spec.add_development_dependency 'rake', '~> 13.0'
53
+ spec.add_development_dependency 'rubocop', '~> 1.63'
47
54
  end
@@ -1,5 +1,5 @@
1
1
  require 'chronicle/etl'
2
- require 'mail'
2
+ require 'chronicle/models'
3
3
  require 'timeout'
4
4
  require 'email_reply_parser'
5
5
  require 'reverse_markdown'
@@ -8,98 +8,97 @@ module Chronicle
8
8
  module Email
9
9
  class EmailTransformer < Chronicle::ETL::Transformer
10
10
  register_connector do |r|
11
+ r.source = :email
12
+ r.type = :message
11
13
  r.description = 'an email object'
12
- r.provider = 'email'
13
- r.identifier = 'email'
14
+ r.from_schema = :extraction
15
+ r.to_schema = :chronicle
14
16
  end
15
17
 
16
18
  setting :body_as_markdown, default: false
17
19
  setting :remove_signature, default: true
18
20
 
19
- def transform
20
- build_messaged
21
+ def transform(record)
22
+ build_messaged(record.data[:raw])
21
23
  end
22
24
 
23
- def id
24
- message.message_id || raise(Chronicle::ETL::UntransformableRecordError, "Email doesn't have an ID")
25
- end
25
+ private
26
26
 
27
- def timestamp
28
- message.date&.to_time || raise(Chronicle::ETL::UntransformableRecordError, "Email doesn't have a timestamp")
29
- end
27
+ def build_messaged(email)
28
+ timestamp = email.date&.to_time || raise(Chronicle::ETL::UntransformableRecordError,
29
+ "Email doesn't have a timestamp")
30
30
 
31
- private
31
+ email.message_id || raise(Chronicle::ETL::UntransformableRecordError, "Email doesn't have an ID")
32
32
 
33
- def message
34
- @message ||= Mail.new(@extraction.data[:email])
33
+ Chronicle::Models::CommunicateAction.new do |r|
34
+ r.end_time = timestamp
35
+ r.agent = build_agent(email[:from])
36
+ r.source = 'email'
37
+ r.source_id = email.message_id
38
+ r.object = build_message(email)
39
+ end
35
40
  end
36
41
 
37
- def build_messaged
38
- record = ::Chronicle::ETL::Models::Activity.new
39
- record.verb = 'messaged'
40
- record.provider = 'email'
41
- record.provider_id = id
42
- record.end_at = timestamp
42
+ def build_agent(from)
43
+ raise(Chronicle::ETL::UntransformableRecordError, "Can't determine email sender") unless from&.addrs&.any?
43
44
 
44
- record.dedupe_on << [:verb, :provider, :provider_id]
45
-
46
- record.actor = build_actor
47
- record.involved = build_message
48
- record
45
+ build_person(from.addrs.first)
49
46
  end
50
47
 
51
- def build_actor
52
- # sometimes From: fields are malformed and we can't build an
53
- # actor out of it.
54
- raise(Chronicle::ETL::UntransformableRecordError, "Can't determine email sender") unless message[:from]&.addrs&.any?
48
+ def build_message(email)
49
+ Chronicle::Models::Message.new do |r|
50
+ r.name = clean_subject(email.subject)
51
+ r.text = clean_body(email)
52
+ r.source = 'email'
53
+ r.source_id = email.message_id
55
54
 
56
- record = ::Chronicle::ETL::Models::Entity.new
57
- record.represents = 'identity'
58
- record.provider = 'email'
59
- record.slug = message[:from].addrs.first.address
60
- record.title = message[:from].addrs.first.display_name
55
+ r.recipient = email[:to]&.addrs&.map { |addr| build_person(addr) }
61
56
 
62
- record.dedupe_on << [:represents, :provider, :slug]
57
+ # TODO: handle email references
58
+ # TODO: handle email account owner
59
+ # TODO: handle attachments
63
60
 
64
- record
61
+ r.dedupe_on << %i[source source_id type]
62
+ end
65
63
  end
66
64
 
67
- def build_message
68
- record = ::Chronicle::ETL::Models::Entity.new
69
- record.represents = 'message'
70
- record.title = clean_subject(message.subject)
71
- record.body = clean_body(message)
72
- record.provider = 'email'
73
- record.provider_id = id
74
-
75
- # TODO: handle consumer
76
- # TODO: handle email references
77
- # TODO: handle email account owner
78
- # TODO: handle attachments
79
-
80
- record
65
+ def build_person(addr)
66
+ Chronicle::Models::Person.new do |r|
67
+ r.source = 'email'
68
+ r.slug = addr.address
69
+ r.name = addr.display_name
70
+ r.dedupe_on << %i[represents provider slug]
71
+ end
81
72
  end
82
73
 
83
74
  def clean_subject(subject)
84
- subject&.encode("UTF-8", invalid: :replace, undef: :replace)
75
+ subject&.encode('UTF-8', invalid: :replace, undef: :replace)
85
76
  end
86
77
 
87
- def clean_body message
88
- # FIXME: this all needs to be refactored
78
+ def clean_body(message)
79
+ # FIXME: this all needs to be refactored
89
80
  if message.multipart?
90
- body = message.text_part&.decoded rescue Mail::UnknownEncodingType
81
+ body = begin
82
+ message.text_part&.decoded
83
+ rescue StandardError
84
+ Mail::UnknownEncodingType
85
+ end
91
86
  else
92
- body = message.body&.decoded rescue Mail::UnknownEncodingType
87
+ body = begin
88
+ message.body&.decoded
89
+ rescue StandardError
90
+ Mail::UnknownEncodingType
91
+ end
93
92
  body = body_to_markdown if @config.body_as_markdown
94
93
  end
95
94
 
96
95
  return if body == Mail::UnknownEncodingType
97
- return unless body && body != ""
96
+ return unless body && body != ''
98
97
 
99
98
  body = body_without_signature(body) if @config.remove_signature
100
99
 
101
100
  # Force UTF-8 encoding
102
- body.encode("UTF-8", invalid: :replace, undef: :replace)
101
+ body.encode('UTF-8', invalid: :replace, undef: :replace)
103
102
  end
104
103
 
105
104
  def body_to_markdown(body)
@@ -111,11 +110,11 @@ module Chronicle
111
110
  def body_without_signature(body)
112
111
  # FIXME: regex in EmailReplyParse gem seems to get into infinite loops
113
112
  # with certain long bodies that have binary data
114
- parsed_body = Timeout::timeout(5) do
113
+ Timeout.timeout(5) do
115
114
  EmailReplyParser.parse_reply(body)
116
115
  end
117
- rescue Timeout::Error, StandardError => e
118
- return body
116
+ rescue Timeout::Error, StandardError
117
+ body
119
118
  end
120
119
  end
121
120
  end
@@ -1,12 +1,14 @@
1
1
  require 'net/imap'
2
+ require 'mail'
2
3
 
3
4
  module Chronicle
4
5
  module Email
5
6
  class IMAPExtractor < Chronicle::ETL::Extractor
6
7
  register_connector do |r|
7
- r.provider = 'email'
8
- r.description = 'imap server'
9
- r.identifier = 'imap'
8
+ r.source = :email
9
+ r.type = :message
10
+ r.strategy = :imap
11
+ r.description = 'IMAP server'
10
12
  end
11
13
 
12
14
  setting :host, required: true, default: 'imap.gmail.com'
@@ -28,7 +30,15 @@ module Chronicle
28
30
  def extract
29
31
  @message_ids.each do |message_id|
30
32
  message = fetch_message(message_id)
31
- yield Chronicle::ETL::Extraction.new(data: { email: message.attr["BODY[]"]} )
33
+ email = Mail.new(message.attr['BODY[]'])
34
+ data = {
35
+ raw: email,
36
+ time: email.date&.to_time,
37
+ subject: email.subject,
38
+ from: email&.from&.join(', '),
39
+ to: email&.to&.join(', ')
40
+ }
41
+ yield build_extraction(data:)
32
42
  end
33
43
  end
34
44
 
@@ -39,31 +49,32 @@ module Chronicle
39
49
  connection.login(@config.username, @config.password)
40
50
  connection.select(@config.mailbox)
41
51
  connection
42
- rescue Net::IMAP::NoResponseError => e
43
- raise(Chronicle::ETL::ExtractionError, "Error connecting to IMAP server. Please check username and password")
52
+ rescue Net::IMAP::NoResponseError
53
+ raise(Chronicle::ETL::ExtractionError, 'Error connecting to IMAP server. Please check username and password')
44
54
  end
45
55
 
46
56
  def fetch_message_ids
47
57
  keys = gmail_mode? ? search_keys_gmail : search_keys_default
48
- @connection.search(keys)
49
- rescue Net::IMAP::BadResponseError => e
50
- raise(Chronicle::ETL::ExtractionError, "Error searching IMAP server for messages")
58
+ message_ids = @connection.search(keys)
59
+ message_ids = message_ids.first(@config.limit) if @config.limit
60
+ message_ids
61
+ rescue Net::IMAP::BadResponseError
62
+ raise(Chronicle::ETL::ExtractionError, 'Error searching IMAP server for messages')
51
63
  end
52
64
 
53
65
  def fetch_message(message_id)
54
- response = @connection.fetch(3100020, "BODY.PEEK[]")
55
- raise(Chronicle::ETL::ExtractionError, "Error loading message") unless response
66
+ response = @connection.fetch(message_id, 'BODY.PEEK[]')
67
+ raise(Chronicle::ETL::ExtractionError, 'Error loading message') unless response
56
68
 
57
- return response[0]
69
+ response[0]
58
70
  end
59
71
 
60
72
  def search_keys_gmail
61
73
  # Gmail offers an extension to IMAP that lets us use gmail queries
62
- q = ""
63
74
 
64
75
  # First, we ignore drafts beacuse they break a lot of assumptions we
65
76
  # make when when processing emails (lack of timestamps, ids, etc)
66
- q = "-label:draft"
77
+ q = '-label:draft'
67
78
 
68
79
  # We use UNIX timestamps in gmail filters which let us do more precise
69
80
  # since/until compared with date-based imap filters
@@ -71,14 +82,14 @@ module Chronicle
71
82
  q += " before:#{@config.until.to_i}" if @config.until
72
83
  q += " #{@config.search_query}" if @config.search_query
73
84
 
74
- ["X-GM-RAW", q]
85
+ ['X-GM-RAW', q]
75
86
  end
76
87
 
77
88
  def search_keys_default
78
89
  keys = []
79
90
  # TODO: test out non-gmail IMAP searching (for @config.search_query)
80
91
  keys += ['SINCE', Net::IMAP.format_date(@config.since)] if @config.since
81
- keys += ['BEFORE', Net::IMAP.format_date(@config.until)] if @config.until
92
+ keys + ['BEFORE', Net::IMAP.format_date(@config.until)] if @config.until
82
93
  end
83
94
 
84
95
  def gmail_mode?
@@ -86,4 +97,4 @@ module Chronicle
86
97
  end
87
98
  end
88
99
  end
89
- end
100
+ end
@@ -6,9 +6,10 @@ module Chronicle
6
6
  module Email
7
7
  class MboxExtractor < Chronicle::ETL::Extractor
8
8
  register_connector do |r|
9
- r.provider = 'email'
9
+ r.source = :email
10
+ r.type = :message
11
+ r.strategy = :mbox
10
12
  r.description = 'an .mbox file'
11
- r.identifier = 'mbox'
12
13
  end
13
14
 
14
15
  setting :input, required: true
@@ -40,14 +41,20 @@ module Chronicle
40
41
  #
41
42
  # TODO: make this thread-safe (one tmp file per email?)
42
43
  file.each do |line|
43
- if line =~ NEW_EMAIL_REGEX
44
- if File.size(tmp) > 0
45
- tmp.rewind
46
- email = tmp.read
47
- yield Chronicle::ETL::Extraction.new(data: { email: email} )
48
- tmp.truncate(0)
49
- tmp.rewind
50
- end
44
+ if line =~ (NEW_EMAIL_REGEX) && File.size(tmp).positive?
45
+ tmp.rewind
46
+
47
+ email = Mail.new(tmp.read)
48
+ data = {
49
+ raw: email,
50
+ time: email.date&.to_time,
51
+ subject: email.subject,
52
+ from: email&.from&.join(', '),
53
+ to: email&.to&.join(', ')
54
+ }
55
+ yield build_extraction(data:)
56
+ tmp.truncate(0)
57
+ tmp.rewind
51
58
  end
52
59
  tmp.write(line)
53
60
  end
@@ -1,5 +1,5 @@
1
1
  module Chronicle
2
2
  module Email
3
- VERSION = "0.2.2"
3
+ VERSION = '0.3.0'.freeze
4
4
  end
5
5
  end
@@ -1,7 +1,7 @@
1
- require "chronicle/email/version"
2
- require "chronicle/email/email_transformer"
3
- require "chronicle/email/mbox_extractor"
4
- require "chronicle/email/imap_extractor"
1
+ require 'chronicle/email/version'
2
+ require 'chronicle/email/email_transformer'
3
+ require 'chronicle/email/mbox_extractor'
4
+ require 'chronicle/email/imap_extractor'
5
5
 
6
6
  module Chronicle
7
7
  module Email
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chronicle-email
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Louis
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-03-31 00:00:00.000000000 Z
11
+ date: 2024-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: chronicle-etl
14
+ name: email_reply_parser
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
@@ -39,47 +39,103 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.7'
41
41
  - !ruby/object:Gem::Dependency
42
- name: email_reply_parser
42
+ name: reverse_markdown
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0.5'
47
+ version: '2.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0.5'
54
+ version: '2.0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: reverse_markdown
56
+ name: chronicle-core
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '2.0'
61
+ version: '0.3'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '2.0'
68
+ version: '0.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: chronicle-etl
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.6'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.6'
83
+ - !ruby/object:Gem::Dependency
84
+ name: net-imap
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: net-smtp
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
69
111
  - !ruby/object:Gem::Dependency
70
112
  name: bundler
71
113
  requirement: !ruby/object:Gem::Requirement
72
114
  requirements:
73
115
  - - "~>"
74
116
  - !ruby/object:Gem::Version
75
- version: '2.1'
117
+ version: '2.3'
76
118
  type: :development
77
119
  prerelease: false
78
120
  version_requirements: !ruby/object:Gem::Requirement
79
121
  requirements:
80
122
  - - "~>"
81
123
  - !ruby/object:Gem::Version
82
- version: '2.1'
124
+ version: '2.3'
125
+ - !ruby/object:Gem::Dependency
126
+ name: pry-byebug
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.10'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.10'
83
139
  - !ruby/object:Gem::Dependency
84
140
  name: rake
85
141
  requirement: !ruby/object:Gem::Requirement
@@ -95,19 +151,19 @@ dependencies:
95
151
  - !ruby/object:Gem::Version
96
152
  version: '13.0'
97
153
  - !ruby/object:Gem::Dependency
98
- name: rspec
154
+ name: rubocop
99
155
  requirement: !ruby/object:Gem::Requirement
100
156
  requirements:
101
157
  - - "~>"
102
158
  - !ruby/object:Gem::Version
103
- version: '3.9'
159
+ version: '1.63'
104
160
  type: :development
105
161
  prerelease: false
106
162
  version_requirements: !ruby/object:Gem::Requirement
107
163
  requirements:
108
164
  - - "~>"
109
165
  - !ruby/object:Gem::Version
110
- version: '3.9'
166
+ version: '1.63'
111
167
  description: Various email importers for chronicle-etl
112
168
  email:
113
169
  - andrew@hyfen.net
@@ -117,6 +173,7 @@ extra_rdoc_files: []
117
173
  files:
118
174
  - ".gitignore"
119
175
  - ".rspec"
176
+ - ".rubocop.yml"
120
177
  - ".travis.yml"
121
178
  - CODE_OF_CONDUCT.md
122
179
  - Gemfile
@@ -138,6 +195,7 @@ metadata:
138
195
  homepage_uri: https://github.com/chronicle-app/chronicle-email
139
196
  source_code_uri: https://github.com/chronicle-app/chronicle-email
140
197
  changelog_uri: https://github.com/chronicle-app/chronicle-email
198
+ rubygems_mfa_required: 'true'
141
199
  post_install_message:
142
200
  rdoc_options: []
143
201
  require_paths:
@@ -146,14 +204,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
146
204
  requirements:
147
205
  - - ">="
148
206
  - !ruby/object:Gem::Version
149
- version: '0'
207
+ version: '3.1'
150
208
  required_rubygems_version: !ruby/object:Gem::Requirement
151
209
  requirements:
152
210
  - - ">="
153
211
  - !ruby/object:Gem::Version
154
212
  version: '0'
155
213
  requirements: []
156
- rubygems_version: 3.3.3
214
+ rubygems_version: 3.4.10
157
215
  signing_key:
158
216
  specification_version: 4
159
217
  summary: Email importer for Chronicle