Class: Heathrow::OAuth2Smtp

Inherits:
Object
  • Object
show all
Defined in:
lib/heathrow/oauth2_smtp.rb

Overview

OAuth2 SMTP module - integrated version of gmail_smtp Handles OAuth2 authentication for Gmail and compatible services

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(from_address = nil, config = {}) ⇒ OAuth2Smtp

Returns a new instance of OAuth2Smtp.



34
35
36
37
38
39
40
41
42
# File 'lib/heathrow/oauth2_smtp.rb', line 34

def initialize(from_address = nil, config = {})
  cfg = Heathrow::Config.instance
  @safe_dir = config['safe_dir'] || cfg&.rc('safe_dir', File.join(Dir.home, '.heathrow', 'mail'))
  @default_email = config['default_email'] || cfg&.rc('default_email', '')
  @oauth2_script = config['oauth2_script'] || cfg&.rc('oauth2_script', File.expand_path('~/bin/oauth2.py'))
  @log_file_path = File.join(@safe_dir, '.smtp.log')
  @from_address = from_address || @default_email
  @log_file = File.open(@log_file_path, 'a') if File.exist?(@safe_dir) && File.writable?(@safe_dir)
end

Instance Attribute Details

#from_addressObject (readonly)

Returns the value of attribute from_address.



32
33
34
# File 'lib/heathrow/oauth2_smtp.rb', line 32

def from_address
  @from_address
end

#log_fileObject (readonly)

Returns the value of attribute log_file.



32
33
34
# File 'lib/heathrow/oauth2_smtp.rb', line 32

def log_file
  @log_file
end

Class Method Details

.send_message(from, to, subject, body, in_reply_to = nil) ⇒ Object

Class method for easy sending



237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/heathrow/oauth2_smtp.rb', line 237

def self.send_message(from, to, subject, body, in_reply_to = nil)
  mail = Mail.new do
    from     from
    to       to
    subject  subject
    body     body
  end
  
  if in_reply_to
    mail['In-Reply-To'] = in_reply_to
    mail['References'] = in_reply_to
  end
  
  oauth2 = new(from)
  oauth2.send(mail)
end

Instance Method Details

#get_oauth2_tokenObject

Get OAuth2 access token using stored credentials



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/heathrow/oauth2_smtp.rb', line 84

def get_oauth2_token
  # Find the correct credential files
  json_file = find_credential_file('.json')
  txt_file = find_credential_file('.txt')
  
  unless json_file && txt_file
    log "Credential files not found for #{from_address}"
    return nil
  end
  
  log "Using #{json_file}"
  
  begin
    # Parse the JSON credentials
    credentials = JSON.parse(File.read(json_file))
    client_id = credentials.dig('web', 'client_id') || credentials.dig('installed', 'client_id')
    client_secret = credentials.dig('web', 'client_secret') || credentials.dig('installed', 'client_secret')
    
    # Read the refresh token
    refresh_token = File.read(txt_file).strip
    
    # Call oauth2.py to get access token
    if File.exist?(@oauth2_script)
      get_token_via_script(client_id, client_secret, refresh_token)
    else
      # Fallback to direct API call if script not available
      get_token_via_api(client_id, client_secret, refresh_token)
    end
    
  rescue => e
    log "Error getting token: #{e.message}"
    nil
  end
end

#send(mail_object, recipients = nil) ⇒ Object

Send email using OAuth2 authentication



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/heathrow/oauth2_smtp.rb', line 45

def send(mail_object, recipients = nil)
  begin
    log "Mail to send: SUBJECT: #{mail_object.subject}"
    log "FROM: #{from_address}"
    
    # Extract recipients from mail object if not provided
    if recipients.nil?
      recipients = []
      recipients += Array(mail_object.to) if mail_object.to
      recipients += Array(mail_object.cc) if mail_object.cc
      recipients.uniq!
    end
    
    log "TO: #{recipients.inspect}"
    
    # Get OAuth2 access token
    token = get_oauth2_token
    
    unless token
      error_msg = "Failed to get OAuth2 token for #{from_address}"
      log error_msg
      return { success: false, message: error_msg }
    end
    
    log "Token obtained for #{from_address}"
    
    # Send via Gmail SMTP with OAuth2
    send_via_smtp(mail_object, token, recipients)
    
  rescue => e
    error_msg = "OAuth2 SMTP error: #{e.message}"
    log error_msg
    { success: false, message: error_msg }
  ensure
    @log_file&.close
  end
end