How do I send an email with an attachment without first creating a file using ruby-gmail? - ruby

I'm using the ruby-gmail gem to send mails.
What I'd like to do is send a ruby hash as a json file.
Example:
require 'gmail'
require 'json'
hash = {'foo' => 'bar}
Gmail.new(<EMAIL>, <PASSWORD>) do |gmail|
gmail.deliver do
to <RECIPIENT>
subject <SUBJECT>
text_part do
body <EMAIL MESSAGE>
end
add_file hash.to_json
end
end
When I try this it simply sends the mail without the attachment.
What could I try next?
Edit:
I want to do this without first creating a file.

You'd need to create the file before you can send it in your add_file method:
hash = {'foo' => 'bar'}
File.open("filename.json","w") do |f|
f.write(hash.to_json)
end
then:
Gmail.new(<EMAIL>, <PASSWORD>) do |gmail|
gmail.deliver do
to <RECIPIENT>
subject <SUBJECT>
text_part do
body <EMAIL MESSAGE>
end
add_file 'path/to/filename.json`
end
end

If you use the "gmail" gem (https://rubygems.org/gems/gmail), then you can add a file with name and content parameters rather than having to actually create a local file. For example:
Gmail.connect(<EMAIL>, <PASSWORD>) do |gmail|
gmail.deliver do
to(<RECIPIENT>)
subject(<SUBJECT>)
text_part do
body(<TEXT_BODY>)
end
html_part do
content_type('text/html; charset=UTF-8')
body(<HTML_BODY>)
end
add_file({filename: <FILE_NAME>, content: <FILE_CONTENT>})
end
end

Related

Zero Bytes Sent When Sending Axlsx Gem Generated File From Sinatra

Attempting to prompt a download window and stream an XLSX file using Ruby Sinatra and the AXLSX gem, my excel file serializes successfully to local file, so I know its a valid excel doc, but I need it to transfer content to the end user. There haven't been any docs online with examples of AXLS and Sinatra used together, only rails. Help is appreciated!
class Downloads < Sinatra::Base
get '/downloads/report' do
## ...
Axlsx::Package.new do |p|
p.workbook.add_worksheet(name: 'tab name') do |sheet|
## ...
end
content_type 'application/xlsx'
attachment 'cost-code-dashboard.xlsx'
p.to_stream # unsuccessful
# p.to_stream.read # unsuccessful as well
end
end
end
I have also tried the following snippet unsuccessfully
Axlsx::Package.new do |p|
## ...
send_file p.to_stream.read, type: "application/xlsx", filename: "cost-code-dashboard.xlsx"
end
It appears that the issue had everything to do with how Axlsx::Package.new was called, the helper functions were not available inside Axlsx, the following solution worked - online documentation said that the below content_type was better
get '/downloads' do
content_type :'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
p = Axlsx::Package.new
p.workbook.add_worksheet(name: 'Test') do |sheet|
sheet.add_row ['Hello world']
end
p.to_stream
end

set REPLY-TO in email pony ruby

we have our API built in Ruby with Sinatra gem. and using Pony for sending emails. I want to set parameter reply-to. i have tried every possibility, even the way Pony gem docs say but its not working at all..
Our mailer code is
require 'logjam'
require 'pony'
module Evercam
module Mailers
class Mailer
LogJam.apply(self, "actors")
##templates = {}
def initialize(inputs)
#inputs = inputs
end
def erb(name)
ERB.new(template(name)).result(binding)
end
private
def template(name)
##templates[name] ||= File.read(
File.expand_path(File.join('.', name))
)
end
def method_missing(name)
if #inputs.keys.include?(name)
#inputs[name]
end
end
def self.method_missing(name, *inputs)
if self.method_defined?(name) && inputs[0]
begin
opts = self.new(inputs[0]).send(name)
mail = Evercam::Config[:mail].merge(opts)
Pony.mail(mail)
rescue Exception => e
log.warn(e)
end
end
end
end
end
end
require_relative 'mailer'
module Evercam
module Mailers
class UserMailer < Mailer
def confirm
{
to: user.email,
subject: 'Evercam Confirmation',
html_body: erb('templates/emails/user/confirm.html.erb'),
body: erb('templates/emails/user/confirm.txt')
}
end
def share
{
to: email,
subject: "#{user.fullname} has shared a camera with you",
html_body: erb('templates/emails/user/camera_shared_notification.html.erb'),
attachments: attachments,
reply_to: sharer
}
end
def share_request
{
to: email,
subject: "#{user.fullname} has shared a camera with you",
html_body: erb('templates/emails/user/sign_up_to_share_email.html.erb'),
attachments: attachments,
reply_to: sharer
}
end
def interested
{
to: 'signups#evercam.io',
subject: 'Signup on evercam.io',
body: erb('templates/emails/user/interested.txt')
}
end
def app_idea
{
to: 'garrett#evercam.io',
subject: 'Marketplace idea on evercam.io',
body: erb('templates/emails/user/app_idea.txt')
}
end
def create_success
{
to: archive.user.email,
subject: "Archive #{archive.title} is ready.",
html_body: erb('templates/emails/user/archive_create_completed.html.erb'),
attachments: attachments
}
end
def create_fail
{
to: archive.user.email,
subject: "Archive #{archive.title} failed.",
html_body: erb('archive_creation_failed.html.erb'),
attachments: attachments
}
end
end
end
end
the reply_to in share and in share_request isn't working at all.. any help will be appreciated. thanks
The question seems old, but I stumbled upon it when I was asking myself the same question.
I finally went back to the pony git page and found the answer in the documentation.
List Of Options
You can get a list of options from Pony directly:
Pony.permissable_options
Options passed pretty much directly to Mail
attachments # see Attachments section
bcc
body # the plain text body
body_part_header # see Custom headers section
cc
charset # In case you need to send in utf-8 or similar
content_type
from
headers # see Custom headers section
html_body # for sending html-formatted email
html_body_part_header # see Custom headers section
message_id
reply_to #This one seems to be the one we're looking for. Not yet tested.
sender # Sets "envelope from" (and the Sender header)
smtp_envelope_to
subject
text_part_charset # for multipart messages, set the charset of the text part
to

Read parameters via POST with Ruby + Sinatra + MongoDB

I'm creating a simple API with Sinatra + Ruby + MongoDB, working via GET not have problems, but via POST yes... I try to receive params but this come in empty, I don't know if I'm doing thing not good. I am not working with view html, just request and response JSON. I use POSTMAN for pass parameters via POST, but nothing.
Code: app.rb
require 'rubygems'
require 'sinatra'
require 'mongo'
require 'json/ext'
require './config/Database'
require_relative 'routes/Estudiantes'
require_relative 'routes/OtherRoute
Code Estudiantes.rb
# Rest Collection Student
collection = settings.mongo_db['estudiantes']
# Finding
get '/estudiantes/?' do
content_type :json
collection.find.to_a.to_json
end
# find a document by its ID
get '/estudiante/:id/?' do
content_type :json
collection.find_one(:_id => params[:id].to_i).to_json
end
# Inserting
post '/new_estudiante/?' do
content_type :json
student = params # HERE
puts 'Parameters: ' + student
new_id = collection.insert student
document_by_id(new_id)
end
# Updating
post '/update_name/:id/?' do
content_type :json
id = BSON::ObjectId.from_string(params[:id].to_s)
puts 'ID: ' + params[:id].to_s
name = params[:name].to_s # HERE
age = params[:age].to_i # HERE
puts 'Name and Age: ' + name + age.to_s
collection.update({:_id => id}, {'$set' => {:name => name, :age => age} })
document_by_id(id)
end
post '/post/?' do
puts params[:name].to_json # HERE
end
Thanks
Solution:
You should apply a JSON.parse and then read parameter
code
post '/post/?' do
params = JSON.parse request.body.read
puts params['name']
end

clean /tmp when send_file is over

I have a Redmine plugin. I create a temporary file in /tmp, then I send it with File.open. I want to delete the temporary file when user has download it. How can I do ?
My code (in a controller):
File.open(filelocation, 'r') do |file|
send_file file, :filename => filename, :type => "application/pdf", :disposition => "attachment"
end
If I remove the file after File.open, it doesn't work.
EDIT
In my controller I do:
def something
temp = Tempfile.new(['PDF_','.pdf'])
# ... some code that modify my pdf ...
begin
File.open(temp.path, 'r') do |file|
send_file file, :filename => temp.path, :type => "application/pdf", :disposition => "attachment"
end
ensure
temp.close
temp.unlink
end
end
My temporary file is remove, but not in the end of my code: the File.open return a damage PDF.
I use send_data instead of send_file, then I delete the file. send_data will block until the data is sent, allowing File.delete request to succeed.
file = temp.path
File.open(file, 'r') do |f|
send_data f.read.force_encoding('BINARY'), :filename => filename, :type => "application/pdf", :disposition => "attachment"
end
File.delete(file)
source: In Ruby on Rails, After send_file method delete the file from server
Call send_file can be offloaded to a web server, therefore it can return asynchronously. Doing anything in tempfile block is dangerous as well as trying to close and unlink the file. When using send_file, the only option is to give up on cleaning the temporary files within the web process.
Consider using the Tempfile class for your job:
Tempfile.create('foo', '/tmp') do |f|
... do something with f ...
end
It's included in standard library and cleanup occur automatically when the block is closed.
Reference:
http://www.ruby-doc.org/stdlib-2.1.1/libdoc/tempfile/rdoc/index.html

Ruby scraper. How to export to CSV?

I wrote this ruby script to scrape product info from the manufacturer website. The scraping and storage of the product objects in an array works, but I can't figure out how to export the array data to a csv file. This error is being thrown:
scraper.rb:45: undefined method `send_data' for main:Object (NoMethodError)
I do not understand this piece of code. What's this doing and why isn't it working right?
send_data csv_data,
:type => 'text/csv; charset=iso-8859-1; header=present',
:disposition => "attachment; filename=products.csv"
Full code:
#!/usr/bin/ruby
require 'rubygems'
require 'anemone'
require 'fastercsv'
productsArray = Array.new
class Product
attr_accessor :name, :sku, :desc
end
# Scraper Code
Anemone.crawl("http://retail.pelicanbayltd.com/") do |anemone|
anemone.on_every_page do |page|
currentPage = Product.new
#Product info parsing
currentPage.name = page.doc.css(".page_headers").text
currentPage.sku = page.doc.css("tr:nth-child(2) strong").text
currentPage.desc = page.doc.css("tr:nth-child(4) .item").text
if currentPage.sku =~ /#\d\d\d\d/
currentPage.sku = currentPage.sku[1..-1]
productsArray.push(currentPage)
end
end
end
# CSV Export Code
products = productsArray.find(:all)
csv_data = FasterCSV.generate do |csv|
# header row
csv << ["sku", "name", "desc"]
# data rows
productsArray.each do |product|
csv << [product.sku, product.name, product.desc]
end
end
send_data csv_data,
:type => 'text/csv; charset=iso-8859-1; header=present',
:disposition => "attachment; filename=products.csv"
If you are new to Ruby, you should be using Ruby 1.9 or later, in which case you can use the built-in CSV output which builds in fast csv plus l18n support:
require 'csv'
CSV.open('filename.csv', 'w') do |csv|
csv << [sku, name, desc]
end
http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV.html
File.open('filename.csv', 'w') do |f|
f.write(csv_data)
end
It probably makes more sense to do:
#csv = FasterCSV.open('filename.csv', 'w')
and then write to it as you go along:
#csv << [sku, name, desc]
that way if your script crashes halfway through you've at least got half of the data.

Resources