# frozen_string_literal: true # Copyright (c) 2018-2020 Yegor Bugayenko # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the 'Software'), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. require 'English' require 'mail' require 'uuidtools' require 'liquid' require 'csv' require 'tmpdir' require 'redcarpet' require 'redcarpet/render_strip' require 'rainbow' require_relative 'version' # Rumble main script. # Author:: Yegor Bugayenko (yegor256@gmail.com) # Copyright:: Copyright (c) 2018-2020 Yegor Bugayenko # License:: MIT class Rumble::CLI # Make an instance. def initialize(opts) @opts = opts end # Send a letter, reading options from the opts. def send letter = Liquid::Template.parse( File.read(File.expand_path(@opts[:letter])) ) skip = @opts[:skip] ? File.readlines(@opts[:skip]).map(&:strip) : [] if @opts[:test] rcpt = [] rcpt[@opts['col-first'].to_i] = 'John' rcpt[@opts['col-last'].to_i] = 'Doe' rcpt[@opts['col-email'].to_i] = @opts[:test] emails = [rcpt] else raise '--csv is required' unless @opts[:csv] emails = CSV.read(@opts[:csv]) end total = 0 sent = [] ignore = !@opts[:resume].nil? && !@opts[:test] from = @opts[:from].strip puts "Sending #{emails.length} email(s) as #{from}" domain = from.strip.gsub(/^.+@|>$/) emails.each do |array| email = array[@opts['col-email'].to_i] unless email puts "Email is #{Rainbow('absent').red} \ at the column ##{@opts['col-email'].to_i}: #{array}" next end email = email.strip.downcase if sent.include?(email) puts "#{Rainbow('Duplicate').red} at: #{array}" next end sent.push(email) first = (array[@opts['col-first'].to_i] || '').strip last = (array[@opts['col-last'].to_i] || '').strip first, last = first.split(' ', 2) if last.empty? && first.include?(' ') name = "#{first.strip} #{last.strip}".strip address = email address = "#{name} <#{email}>" unless name.empty? print "Sending to #{address}... " markdown = letter.render( 'email' => email, 'first' => first, 'last' => last ) html = Redcarpet::Markdown.new(Redcarpet::Render::HTML) .render(markdown) text = Redcarpet::Markdown.new(Redcarpet::Render::StripDown) .render(markdown) if ignore if @opts[:resume].downcase != email puts "#{Rainbow('ignored').orange}, waiting for #{@opts[:resume]}" next end ignore = false end if skip.include?(email) puts Rainbow('skipped').red next end subject = @opts[:subject] mail = Mail.new do from from to address subject subject message_id "<#{UUIDTools::UUID.random_create}@#{domain}>" text_part do content_type 'text/plain; charset=UTF-8' body text end html_part do content_type 'text/html; charset=UTF-8' body html end end if @opts[:attach] Dir.mktmpdir do |dir| `#{@opts[:attach]} "#{email}" "#{name}" "#{dir}"` raise 'Failed to exec' unless $CHILD_STATUS.success? Dir[File.join(dir, '*')].each do |f| mail.add_file(filename: File.basename(f), content: IO.read(f)) end end end mail.deliver! unless @opts[:dry] total += 1 puts "#{Rainbow('done').green} ##{total}" end puts "Processed #{sent.size} emails" end end