Attempt at authenticated SMTP in Ruby - ruby

I've looked at all the SMTP ruby-docs and can't figure out where I'm going wrong:
def send(username, password, data, toAddress, fromAddress)
smtp = Net::SMTP.new('my.smtp.host', 25)
smtp.start('thisisunimportant', username, password, "plain") do |sender|
sender.send_message(data, fromAddress, toAddress)
end
end
send(user, pass, rcpt, "Hey!")
Gives an unexpected kind of error:
/usr/lib/ruby/1.9.1/net/smtp.rb:725:in authenticate': wrong number of arguments (3 for 4) (ArgumentError)
from /usr/lib/ruby/1.9.1/net/smtp.rb:566:indo_start'
from /usr/lib/ruby/1.9.1/net/smtp.rb:531:in start'
from gmx_pop.rb:24:insend'
from gmx_pop.rb:30:in `'
I've tried kicking my computer a couple times but the problem persists.

Here's a description of the Net::SMTP#start call:
http://ruby-doc.org/stdlib-1.9.1/libdoc/net/smtp/rdoc/Net/SMTP.html#method-i-start
the page mentions that you can just do SMTP.start to do everything at once.
Look like you are missing the port parameter. Try port 587 for secure authentication, if that doesn't work, port 25. (check the tutorial mentioned below)
Your call should look like this:
message_body = <<END_OF_EMAIL
From: Your Name <your.name#gmail.com>
To: Other Email <other.email#somewhere.com>
Subject: text message
This is a test message.
END_OF_EMAIL
server = 'smtp.gmail.com'
mail_from_domain = 'gmail.com'
port = 587 # or 25 - double check with your provider
username = 'your.name#gmail.com'
password = 'your_password'
smtp = Net::SMTP.new(server, port)
smtp.enable_starttls_auto
smtp.start(server,username,password, :plain)
smtp.send_message(message_body, fromAddress, toAddress) # see note below!
Important:
Please note that you need to add To: , From: , Subject: headers to your message_body!
the Message-Id: and Date: headers will be added by your SMTP server
Check also:
Tutorial : http://www.java-samples.com/showtutorial.php?tutorialid=1121
the source code for Net::SMTP under ~/.rvm/src/ruby-1.9.1*/lib/net/smtp.rb
(Ruby) Getting Net::SMTP working with Gmail...?
Another way to send emails from Ruby:
You can use the ActionMailer gem from Rails to send emails from Ruby (without Rails).
At first this seems like overkill, but it makes it much easier, because you don't have to format the message body with To: , From: , Subject: , Date: , Message-Id: Headers.
# usage:
# include Email
#
# TEXT EMAIL :
# send_text_email( 'sender#somewhere.com', 'sender#somewhere.com,receiver#other.com', 'test subject', 'some body text' )
# HTML EMAIL :
# send_html_email( 'sender#somewhere.com', 'sender#somewhere.com,receiver#other.com', 'test subject', '<html><body><h1>some title</h1>some body text</body></html>' )
require 'action_mailer'
# ActionMailer::Base.sendmail_settings = {
# :address => "Localhost",
# :port => 25,
# :domain => "yourdomain.com"
# }
ActionMailer::Base.smtp_settings = { # if you're using GMail
:address => 'smtp.gmail.com',
:port => 587,
:domain => 'gmail.com',
:user_name => "your-username#gmail.com"
:password => "your-password"
:authentication => "plain",
:enable_starttls_auto => true
}
class SimpleMailer < ActionMailer::Base
def simple_email(the_sender, the_recepients, the_subject, the_body , contenttype = nil)
from the_sender
recipients the_recepients
subject the_subject
content_type contenttype == 'html' ? 'text/html' : 'text/plain'
body the_body
end
end
# see http://guides.rails.info/action_mailer_basics.html
# for explanation of dynamic ActionMailer deliver_* methods.. paragraph 2.2
module Email
# call this with a message body formatted as plain text
#
def send_text_email( sender, recepients, subject, body)
SimpleMailer.deliver_simple_email( sender , recepients , subject , body)
end
# call this with an HTML formatted message body
#
def send_html_email( sender, recepients, subject, body)
SimpleMailer.deliver_simple_email( sender , recepients , subject , body, 'html')
end
endsubject , body, 'html')
end
end
e.g. the code above works if you want to use Gmail's SMTP server to send email via your Gmail account.. Other SMTP servers may need other values for :port, :authentication and :enable_starttls_auto depending on the SMTP server setup

Try this code
Net::SMTP.smtp.start('my.smtp.host', 25, 'mail.from.domain', username, password, :plain) do |smtp|
smtp.send_message data, fromAddress, toAddress
end

Related

Ruby Oauth2.0: client_secret_post not working with ory hydra

I am trying to get a Ruby Oauth2.0 client talking with the Ory Hydra docker-compose 5 minute demo. I am stuck on the client app's authentication code exchange for the token. LOG is below. Looks like the main problem is the following "hashedPassword is not the hash of the given password".
DEBUG LOG FROM HYDRA SERVER
time="2019-06-04T21:32:09Z" level=info msg="started handling request" method=POST remote="172.19.0.2:35482" request=/oauth2/token
hydra_1
time="2019-06-04T21:32:09Z" level=error msg="An error occurred" debug="crypto/bcrypt: hashedPassword is not the hash of the given password" description="Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method)" error=invalid_client
hydra_1
time="2019-06-04T21:32:09Z" level=info msg="completed handling request" measure#hydra/public: http://127.0.0.1:4444/.latency=92931900 method=POST remote="172.19.0.2:35482" request=/oauth2/token status=401 text_status=Unauthorized took=92.9319ms
I've read up here and it would appear this 'is' possible.
Here is how I register my client 'test-app9' in hydra:
docker-compose -f quickstart.yml exec hydra hydra clients create --endpoint http://127.0.0.1:4445 --id test-app9 --secret secret--skip-tls-verify --grant-types authorization_code,refresh_token,client_credentials,implicit --response-types token,code,id_token --scope profile --callbacks http://127.0.0.1:8088/auth/callback --token-endpoint-auth-method client_secret_post -g client_credentials
I can indeed see the client appearing in the postgres DB from the docker-compose demo. The password 'secret' is hashed in the DB.
Here is my single Sinatra file acting as the Oauth2.0 client:
require 'rubygems'
require 'sinatra'
require 'oauth2'
require 'json'
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
# If you add your authentication in the header then use ~Sclient_secret_basic~T
# If you add your authentication details in the post use ~Sclient_secret_post~T
def client
OAuth2::Client.new('test-app9',
'secret',
# 'c2VjcmV0',
:site => "http://127.0.0.1:4445",
:logger => Logger.new('example.log'),
:authorize_url => "http://127.0.0.1:4444/oauth2/auth",
:token_url => "http://hydra:4444/oauth2/token")
end
set :root, File.dirname(__FILE__)
set :views, Proc.new { File.join(root, "views") }
set :run, true
set :port, 80
get "/" do
erb :index
end
get '/auth' do
authorization_url = client.auth_code.authorize_url(:redirect_uri => redirect_uri, :response_type => "code", :scope => "profile", :state => "pqrst1234")
puts "Redirecting to URL: #{authorization_url.inspect}"
redirect authorization_url
end
get '/auth/callback' do
begin
access_token = client.auth_code.get_token(params[:code], :redirect_uri => redirect_uri, :client_id => "test-app9", :client_secret => 'secret', :headers => {'Authorization' => 'basic_auth_header', 'client_id' => 'test-app9', 'client_secret' => 'c2VjcmV0'} )
api_url = "/me.json"
me = JSON.parse(access_token.get(api_url).body)
erb "<p>Your data:\n#{me.inspect}</p>"
rescue OAuth2::Error => e
erb %(<p>Wassup #{$!}</p><p>Retry</p>)
end
end
get '/auth/failure' do
erb "<h1>Authentication Failed:</h1><h3>message:<h3> <pre>#{params}</pre>"
end
def redirect_uri(path = '/auth/callback', query = nil)
uri = URI.parse(request.url)
uri.path = path
uri.query = query
uri.to_s
end
__END__
So some interesting notes:
It apparently does not matter what secret I initiate the OAuth2 client with. I can use 'secret' or the base64 encoded 'c2VjcmV0' string. Either way I get up to the token exchange portion.
I was shotgunning this and ended up putting the client_id and the client_secret in what I believe is the proper way to set in the headers as well as the body.
I have tried many variations of this. Can't seem to get the correct syntax that the author of this apparently succeeded with OR I'm hitting a bug (doubtful).
Anyone able to help here?
UPDATE
Fixed this myself. Problem was syntax issue when creating my client 'app'. This is the corrected version.
docker-compose -f quickstart.yml exec hydra hydra clients create --endpoint http://127.0.0.1:4445 --id test-app10 --secret secret --skip-tls-verify --grant-types authorization_code,refresh_token,client_credentials,implicit --response-types token,code,id_token --scope profile --callbacks http://127.0.0.1:8088/auth/callback --token-endpoint-auth-method client_secret_post -g client_credentials

Ruby_send the result of scraping through email

With Ruby, my app:
checks if the page status is 200
Parses the PDF files if so
sends via email the result of scraping
Having tested all the parts of the code, everything works fine, except one thing, the mail that is sent doesn't contain the result of my scrpaing;
What is the issue, is it related to the variable #monscrape that may be not recongnised in the final party of the code ?
My code:
require 'open-uri'
require "net/http"
require 'rubygems'
require 'pdf/reader'
require 'mail'
options = { :address => "smtp.gmail.com",
:port => 587,
:domain => 'gmail.com',
:user_name => 'mail#gmail.com',
:password => 'pwd',
:authentication => 'plain',
:enable_starttls_auto => true
}
lien= "http://www.example.com"
url = URI.parse(lien)
req = Net::HTTP.new(url.host, url.port)
res = req.request_head(url.path)
if res.code == "200"
io = open('http://www.example.com')
reader = PDF::Reader.new(io)
reader.pages.each do |page|
res = page.text
#monscrape = res.scan(/text[\s\S]*text/)
end
Mail.defaults do
delivery_method :smtp, options
end
Mail.deliver do
to 'mail#hotmail.com'
from 'Author <mail#gmail.com>'
subject 'testing sendmail'
html_part do
content_type 'text/html; charset=UTF-8'
body '<h1>Please find below the scrape <%= #monscrape %></h1>'
end
end
else
puts "the link doenst work"
end
The problem is the Mail.deliver block is evaluated using instance_eval. Therefore no local instance #variables will be visible to the Mail block.
So #monscrape will always be nil inside the Mail.deliver block.
One solution is to use a local (non-instance) variable instead:
monscrape = "test"
Mail.deliver do
...
body "<h1>Please find below the scrape #{monscrape}</h1>"
...
end
Also note that Mail does not support ERB(!) therefore you cannot use something like <%= monscrape %> in the body. You have to treat it like a normal string using string expansion with double quotes " and not single quotes '.
See further discussion and options here:
Why can't the Mail block see my variable?
You can't use
res = req.request_head(url.path)
when url.path returns "". request_head expects a path of at least "/". That implies you need to fix up the URL being passed so it at least has the root path "/".
url = URI.parse('http://www.example.com')
url.path # => ""
req.request_head(url.path)
*** ArgumentError Exception: HTTP request path is empty
vs.
url = URI.parse('http://www.example.com/')
url.path # => "/"
req.request_head(url.path)
#<Net::HTTPOK 200 OK readbody=true>
The second problem is you're trying to read something as PDF that isn't a PDF file. Example.com returns HTML, which is text. You can't use:
io = open('http://www.example.com')
reader = PDF::Reader.new(io)
Trying to returns "PDF does not contain EOF marker".
It's really important that you understand what types of objects/resources are being returned by a site when you request a URL. You can't declare them willy-nilly and expect code to accept it without errors.

Mandrill - No message exists with id

I'm having an issue using the mandrill API for ruby and i'm not sure if it's a lack of ruby/api understanding on my part of if there's an issue with the mandrill api.
I have this method which sends an email with mandrill, and then I make another api call using the id returned from mandrill.messages.send to make another call to mandrill to get the email header message-id so i can store that in a db table.
Why am I getting the error Mandrill::UnknownMessageError (No message exists with the id '64fba1cce24942dea1ada4f905fd7871'): when the id clearly exists as seen in the comments for the logging events?
# Sends an email to all users for the account_id on the issue
def send_email
require 'mandrill'
...
mandrill = Mandrill::API.new Mandrill::API_KEY
# Email contents
message = {
:subject => self.name,
:from_name => self.account.subdomain,
:text => self.description,
:to => [{
:email => user.email,
:name => user.name
}],
:text => self.description,
:from_email => "noreply#myapp.com",
:headers => {
'reply-to' => 'update#myapp.com'
}
}
results = mandrill.messages.send message # Send email through mandrill
# Loop through results of sent email
results.each do |result|
logger.debug "result id = #{result['_id']}" # LOGS result id = 64fba1cce24942dea1ada4f905fd7871
logger.debug "result = #{result}" # LOGS result = {"email"=>"tomcaflisch#gmail.com", "status"=>"sent", "_id"=>"64fba1cce24942dea1ada4f905fd7871", "reject_reason"=>nil}
id = result['_id'] # Mandrill's internal id from api call results that sent the email
# CAUSES Mandrill::UnknownMessageError (No message exists with the id '64fba1cce24942dea1ada4f905fd7871'):
info = mandrill.messages.content id # Get info for sent email with a specific mandrill id
end
end
I think you just have to give it a little bit of time.
I am facing the same error on messages.info(id).
However, search('*') is finding all messages sent but not providing correct status information.
I think the following snippet of gem code is getting 500 status (instead of 200) when messages.info(id) is called:
def call(url, params={})
params[:key] = #apikey
params = JSON.generate(params)
r = #session.post(:path => "#{#path}#{url}.json", :headers => {'Content-Type' => 'application/json'}, :body => params)
cast_error(r.body) if r.status != 200
return JSON.parse(r.body)
end
Also, gem code is hosted on bitbucket instead of more common github. Not sure how to raise an issue there for support.
Sorry can't be of much help but thought I should share my experience also to get more visibility for the problem.

send email to multiple recipients using net/smtp

I have this code:
require "net/smtp"
MAIL_SERVER = "xxx.ad.xxx.net"
def lib_sending_report(email_hash)
# define message body
message = <<"MESSAGE_END"
From: <#{email_hash[:sender]}>
To: <#{email_hash[:recipients]}>
MIME-Version: 1.0
Content-type: text/html
Subject: #{email_hash[:subject]}
<p>Hi All,</p>
<p>We've just executed a round of load test.</p>
<p>Regards</p>
MESSAGE_END
Net::SMTP.start(MAIL_SERVER) do |smtp|
smtp.send_message message, email_hash[:sender], email_hash[:recipients]
end
end
test = ""
lib_sending_report( {:sender => "abc#xxx.com",
:recipients => "abc#xxxx.com",
:subject => "Load.Test.Report.of.#{test}"} )
When I change :recipients => "abc#xxxx.com" to :recipients => "abc#xxxx.com;efg#xxx.com", it gives me this error:
501 5.5.4 Invalid Address (Net::SMTPSyntaxError)
I can successfully send email when :recipients => "abc#xxxx.com" just have one recipient.
Where am I wrong? It seems that the separator(semicolon) I used is wrong.
I tried to use comma instead of semicolon, but it didn't work
Net::SMTP's send_message takes an array of "To:" address strings.
Per the documentation:
to_addr is a String or Strings or Array of Strings, representing the destination mail address or addresses.
This example from the documentation shows how:
Net::SMTP.start('smtp.example.com') do |smtp|
smtp.send_message msgstr,
'from#example.com',
['dest#example.com', 'dest2#example.com']
end

Ruby Mail gem, how to script mail messages

I have testmail.rb on a CENTOS 5 VM with SELinux permissive and IPtables off:
require 'rubygems'
require 'mail'
options = { :address => "mail.domain.com",
:port => 466,
:domain => 'otherdomain.com',
:user_name => 'somedude#domain.com',
:password => 'topsecret',
:authentication => 'plain',
:enable_starttls_auto => true }
Mail.defaults do
delivery_method :smtp, options
end
mail = Mail.new do
from 'somedude#otherdomain.com'
to 'admin#domain.com'
subject 'This is a test email'
body File.read('body.txt')
end
puts mail.to_s
The result when the script is run is this:
Date: Tue, 30 Nov 2010 12:12:58 -0500
From: somedude#otherdomain.com
To: admin#domain.com
Message-ID: <4cf5309a2f074_284015c5c4de91b8270b2#apvdbs03.3rdomain.local.mail>
Subject: This is a test email
Mime-Version: 1.0
Content-Type: text/plain;
charset=UTF-8
Content-Transfer-Encoding: 7bit
test!
"test!" is the content of body.txt.
No email ever reaches the sent to account. The smtp settings we got from the sent to domain admin. I used telnet to successfully send an email to the domain on the unencrypted port (25) but got no response from the encrypted port (466), possibly because my telnet session was unencrypted?
What are some ways I can see what's going on during the script execution to troubleshoot?
Update:
Tried redirecting: > log.log 2>&1, but that didn't provide any additional info.
You're missing the line to actually send. Try adding
mail.deliver!
to the end of your script.

Resources