How to format email for gmail? - html

I wrapped the email's body in <html><body><pre>. Show original in gmail gives me actually how I want the email to be formatted:
Mime-Version: 1.0
Content-Type: text/html;
charset=UTF-8
Content-Transfer-Encoding: 7bit
Ant run name : Basics of Edumate
Overall result : pass
Ant run took: 4 minutes 15 seconds
--------------------------
Details for all test suits
--------------------------
login : Pass
AddCycleTemplate: Pass
AddCycleTemplate: Pass
AddAcademicYear : Pass
AddAcademicYear : Pass
But the actual email is displayed as one line. Note that space that I use to align : is somehow omitted as well as new lines.
Ant run name : Basics of Edumate Overall result : pass Ant run took: 4 minutes 15 seconds -------------------------- Details for all test suits -------------------------- login : Pass AddCycleTemplate: Pass AddCycleTemplate: Pass AddAcademicYear : Pass AddAcademicYear : Pass
I send the email from ruby using pony.
Any suggestions how to get the formatting inside gmail as desired?

I would recommend to simply use an HTML table to do that.
Just for the sake of answering thoroughly, the code would be something like:
<table>
<tr>
<td>Mime-Version:</td>
<td>1.0</td>
</tr>
<tr>
<td>Content-Type:</td>
<td>text/html;</td>
</tr>
...
</table>
etc..

I think using <br/> for line breaks would work, but there's probably a better solution...

This the was I send html email to gmail. I guess what I was missing was :html_body => body, part of pony's settings.
def email_it(body, subject,to,from)
$smtp = 'mail.com.au'
$smtp_port = 25
Pony.mail(
:to => to,
:from => from,
:subject => subject,
:body => Nokogiri::HTML(body).text,
:html_body => body,
:via => :smtp,
:via_options => {
:address => $smtp,
:port => $smtp_port,
:enable_starttls_auto => false
}
)
end

Related

Google Drive API Notifications - File Watch not Sending Add Notifications - possible reasons?

I just set up Google Drive API Change Notifications, specifying the folderId of a certain shared folder that I have on My Drives. It sends notifications if I change the folder name, but doesn't send notifications if I add files.
I set up the channel successfully, as upon issuing these PHP commands
$client = new Google_Client();
$client->setApplicationName('Some Name');
$client->setAuthConfig( __DIR__ . '/service_account.json');
$client->setScopes(Google_Service_Drive::DRIVE);
$client->fetchAccessTokenWithAssertion();
$token = $client->getAccessToken();
$service = new Google\Service\Drive($client);
$httpclient = new \GuzzleHttp\Client();
$folderid = $someid;
$body = [
'kind' => "api#channel",
'id' => uniqid(),
'type' => 'web_hook',
'resourceId' => $folderid,
'resourceUri' => 'https://www.googleapis.com/drive/v3/files/'.$folderid,
'address' => 'myendpoint'
];
$apiendpoint = 'https://www.googleapis.com/drive/v3/files/' . $folderid . '/watch';
$result = $httpclient->post($apiendpoint, [
'headers' => ['Content-Type' => 'application/json', 'Authorization' => "Bearer {$token['access_token']}"],
'body' => json_encode($body),
"http_errors" => false]);
I see a successful return, and my channel immediately sends a sync message to my endpoint, where I have this
function myendpoint (WP_REST_Request $request) {
$headers= getallheaders();
write_log('in google drive webhook with headers '.print_r($headers, true));
$body = $request->get_body();
write_log('in google drive webhook with body '.print_r($body, true));
global $wpdb;
return http_response_code(200);
}
Via my logging, I see
[07-Nov-2021 12:52:35 UTC] in google drive webhook with headers Array
(
[Host] => courses-test.com
[User-Agent] => APIs-Google; (+https://developers.google.com/webmasters/APIs-Google.html)
[Content-Length] => 0
[Accept] => */*
[Accept-Encoding] => gzip, deflate, br
[X-Forwarded-For] => 66.102.8.121
[X-Forwarded-Proto] => https
[X-Goog-Channel-Expiration] => Sun, 07 Nov 2021 13:51:26 GMT
[X-Goog-Channel-Id] => 6187cbc82a08e
[X-Goog-Message-Number] => 1
[X-Goog-Resource-Id] => resid
[X-Goog-Resource-State] => sync
[X-Goog-Resource-Uri] => https://www.googleapis.com/drive/v3/files/folderid?acknowledgeAbuse=false&supportsAllDrives=false&supportsTeamDrives=false&alt=json
[X-Original-Host] => mydomain
)
I read here
https://developers.google.com/drive/api/v3/push
where it says
"To indicate success, you can return any of the following status codes: 200, 201, 202, 204, or 102."
and hence I am returning return http_response_code(200);
and also read here
https://developers.google.com/drive/api/v3/reference/files/watch
and I don't see anything obvious going on here.
Here
https://developers.google.com/search/docs/advanced/crawling/apis-user-agent?visit_id=637718909398077288-2640249237&rd=1
there is this remark
"Avoid unnecessary retry requests by ensuring that your application is well-designed and responds promptly to notification messages (within seconds)."
Now, when I first set up the channel, my endpoint returns right away, so that would seem to negate the above point.
Also, after I get channel set up, I also run these lines
$optParams = array(
'pageSize' => 10,
'fields' => 'nextPageToken, files(id, name)'
);
$results = $service->files->listFiles($optParams);
and indeed see a listing of files.
So I truly at a loss. When I go into the folder, whose folderId I specified to set up the watch channel, and add a file, or edit a file, I don't receive any notifications. The folder in question is shared, but as I understand, sharing only becomes an issue when dealing with shared drives, which is not my case.
And I read here,
https://developers.google.com/drive/api/v3/push#understanding-drive-api-notification-events
that watching for files being added should indeed work on a file watch, when the file is a folder, since add is one of the events for a resource, and it applies to Files.
**Update:
Ok, I seem to have things working, but not based on an add event. The only thing I changed, is that instead of using Guzzle to make the POST, as I show above, I use this
$channel->setId(uniqid());
$channel->setAddress($body['address']);
$channel->setType('web_hook');
$test = $service->files->watch($folderid, $channel);
Maybe adding some of those extra params in the $body like kind, resourceId, was messing things up when I was using POST via Guzzle. Or now that I know resourceId is not same as folderid, maybe that threw a flag on google's end so that a limited number of notifications were being sent. In any case, just using id', address and type seems to be the way to go, which I think is in the Google Drive Push docs. Just that in those docs, also mention of adding those other params in the request, like 'resourceId'. I suspect if I redo using Guzzle, but specify correct resourceId, or just leave it out and use id', address and type, that it would work.
So now, I get this sort of header in my endpoint when I add a file:
(
[Host] => courses-test.com
[User-Agent] => APIs-Google; (+https://developers.google.com/webmasters/APIs-Google.html)
[Content-Length] => 0
[Accept] => */*
[Accept-Encoding] => gzip, deflate, br
[X-Forwarded-For] => someip
[X-Forwarded-Proto] => https
[X-Goog-Changed] => children
[X-Goog-Channel-Expiration] => Mon, 08 Nov 2021 09:46:10 GMT
[X-Goog-Channel-Id] => chanid
[X-Goog-Message-Number] => num
[X-Goog-Resource-Id] => someid
[X-Goog-Resource-State] => update
[X-Goog-Resource-Uri] => https://www.googleapis.com/drive/v3/files/folderid?acknowledgeAbuse=false&supportsAllDrives=false&supportsTeamDrives=false&alt=json
[X-Original-Host] => mydomain
)
So I can detect [X-Goog-Changed] as being children and just keep track of my current uploaded files and see what the new file is. Or maybe using the fields query string somehow I can directly get the new file id?
Still seems odd that getting info about a new file is such a pain. Maybe it is easier in Google Cloud API and Google wants more people signing up for Cloud. In fact that add event only seems to apply to Cloud buckets.
In short: When watching a folder with files().watch() it is currently not possible to receive notifications about new files added to this folder
There are several workarounds that you can find along with explanations in answers to similar questions:
Use changes().watch():
https://stackoverflow.com/a/26551651/11599789 and https://stackoverflow.com/a/67787626/11599789
Pass the folderId to the token:
https://stackoverflow.com/a/33896300/11599789
Make copy of all file's metadata and query for changes:
https://stackoverflow.com/a/18151189/11599789
Also: There is a relevant feature request on Google's Issue Tracker.
It has been closed due to inactivity, but it is worth "starring" and commenting on it to increase visibility.

How to setup send HTML email with mail gem?

I am sending email using the Mail gem. Here's my code:
require 'mail'
require 'net/smtp'
Mail.defaults do
delivery_method :smtp, { :address => "smtp.arrakis.es",
:port => 587,
:domain => 'webmail.arrakis.com',
:user_name => 'myname#domain.com',
:password => 'pass',
:authentication => 'plain',
:enable_starttls_auto => true }
end
Mail::ContentTypeField.new("text/html") #this doesnt work
msgstr= File.read('text2.txt')
list.each do |entity|
begin
Mail.deliver do
from 'myname#domain.com'
to "#{entity}"
subject 'a good subject'
body msgstr
end
rescue => e
end
end
end
I don't know how to set up the content type, so that I can format my email as html for example. Though I actually just wish to be able to define bold text like my email client does: bold text. Does anybody know which content-type I need to specify in order to achieve this, and how to implement it with mail?
Just a note, the code above works fine for sending plain text email.
From the documentation
Writing and sending a multipart/alternative (html and text) email
Mail makes some basic assumptions and makes doing the common thing as
simple as possible.... (asking a lot from a mail library)
mail = Mail.deliver do
to 'nicolas#test.lindsaar.net.au'
from 'Mikel Lindsaar <mikel#test.lindsaar.net.au>'
subject 'First multipart email sent with Mail'
text_part do
body 'This is plain text'
end
html_part do
content_type 'text/html; charset=UTF-8'
body '<h1>This is HTML</h1>'
end
end
#Simone Carletti's answer is essentially correct, but I was struggling with this and didn't want a plain text portion to my email and a separate HTML portion. If you just want the entire email to be HTML, something like this will work:
mail = Mail.deliver do
to 'nicolas#test.lindsaar.net.au'
from 'Mikel Lindsaar <mikel#test.lindsaar.net.au>'
subject 'First email sent with Mail'
content_type 'text/html; charset=UTF-8'
body '<h1>This is HTML</h1>'
end
I may have missed it, I didn't see anything in the Mail gem documentation describing how to do that, which I would think would be more common than making a multipart message. The documentation only seems to cover plain text messages and multipart messages.

How do you get Amazon SES to send upon submission of form in Padrino

Following the instructions here: http://www.padrinorb.com/guides/padrino-mailer
I have the delivery method added on the app.rb file:
class OscarAffiliate < Padrino::Application
register Padrino::Rendering
register Padrino::Mailer
register Padrino::Helpers
enable :sessions
set :delivery_method, :smtp => {
:address => "email-smtp.us-east-1.amazonaws.com",
:port => 587,
:user_name => 'AKIAIQ5YXCWFKFXFFRZA',
:password => 'AqMNMFecKSYR/TRu8kJgocysAL5SmIUsu2i8u/KAfeF/',
:authentication => :plain,
:enable_starttls_auto => true
}
But via the generation through Padrino and the Mailer generation, I do not have the recommended "sessions" controller in which this should belong:
post :create do
email(:from => "tony#reyes.com", :to => "john#smith.com", :subject => "Welcome!", :body=>"Body")
end
Am I missing something?
I have the form for a basic data collection at an office and just need an email to be sent to 5 recipients with all the form fields in the message body.
Thanks
It appears to me that you're trying to email a person (or multiple people) after a form is submitted. Possibly you're saving information from that form to a database. I think that you are a little confused on how to use Padrino mailers. Allow me to clarify: In order to send an email, using Padrino's mailer functionality, with a full body of content, you must create a Padrino Mailer (I've outlined this below). Then you must configure that mailer so that you may pass variables to it when you call it. Those variables can then be used in the view, which your mailer renders into the email body before sending the email. This is one way of accomplishing what it appears you are trying to do and it is probably the most straight-forward. You can find more information about this procedd under "Mailer Usage" on the help page you provided in your question. I've outlined an example usage, tailored to what I believe your needs are, below.
Instructions
I threw together this code sample and tested it against my AWS account; it should work in production.
In your app/app.rb file, include the following (you have already done so):
set :delivery_method, :smtp => {
:address => 'email-smtp.us-east-1.amazonaws.com',
:port => 587,
:user_name => 'SMTP_KEY_HERE',
:password => 'SMTP_SECRET_HERE',
:authentication => :plain,
:enable_starttls_auto => true
}
Then create a Mailer in app/mailers/affiliate.rb:
# Defines the mailer
DemoPadrinoMailer.mailer :affiliate do
# Action in the mailer that sends the email. The "do" part passes the data you included in the call from your controller to your mailer.
email :send_email do |name, email|
# The from address coinciding with the registered/authorized from address used on SES
from 'your-aws-sender-email#yoursite.com'
# Send the email to this person
to 'recipient-email#yoursite.com'
# Subject of the email
subject 'Affiliate email'
# This passes the data you passed to the mailer into the view
locals :name => name, :email => email
# This is the view to use to redner the email, found at app/views/mailers/affiliate/send_email.erb
render 'affiliate/send_email'
end
end
The Affiliate Mailer's send_email view should be located in app/view/mailers/affiliate/send_email.erb and look like this:
Name: <%= name %>
Email: <%= email %>
Finally, you can call your mailer from inside whatever method (and controller) you're accepting form submissions from. Be sure to replace the strings with actual form data. In this example, I used a POSTed create action, which did not save any data (thus the strings with fake data):
post :create do
# Deliver the email, pass the data in after everything else; here I pass in strings instead of something that was being saved to the database
deliver(:affiliate , :send_email, "John Doe", "john.doe#example.com")
end
I sincerely hope that this helps you in your journey with Padrino, and welcome to the Stack Overflow community!
Sincerely,
Robert Klubenspies

Issue with RoR ActionMailer --cannot send plaintext and HTML emails simultaneously.

I'm having an issue with my Rails application--I'm having trouble sending both a HTML and plaintext version of my email. NOTE: the email does send; however, it's not styled correctly... there is a link to the results below.
It's recommended everywhere that if you want to send HTML you should also send a plain text alternative too. Unfortunately, it appears that I'm doing something wrong, as my application does not allow me to send both HTML and plaintext, without the HTML looking very weird.
here is my mailer model:
class ProjectMembersMailer < ActionMailer::Base
def membership_invitation(membership)
#project = membership.project
#user = membership.user
mail( :subject => %(Invitation to join project #{#project.business_name}),
:from => %("App" <no-reply#appname.com>),
:to => #user.account.email,
:content_type => "text/html" ) do |format|
format.html
format.text
end
end
end
My project_member_mailer views have two files: membership_invitation.html.haml and membership_invitation.text.erb (please note that the second file is using .erb, but even if I convert it to a .haml extension for consistency I get the same error)
Here is picture of that the output looks like when I attempt to send it using the code above. Please note that I removed some of the text.
Basically it looks like it's sending the text version above the html version of the file. Is there an alternate way to sending both plaintext and HTML emails without this happening? Or am I missing something--like, should these emails not be sent simultaneously? Any help would be greatly appreciated. Thank you so much for your time and help!
According to the Action Mailer Rails Guide you do not need to use the "format" method, and should remove the "content-type" parameter too.
mail will automatically detect that there are both html and text templates and will automatically create the email as multipart/alternative
Just try:
mail( :subject => %(Invitation to join project #{#project.business_name}),
:from => %("App" <no-reply#appname.com>),
:to => #user.account.email)
I had the exact same problem, and it can be fixed with just one simple thing. Place format.text over format.html
def membership_invitation(membership)
#project = membership.project
#user = membership.user
mail( :subject => %(Invitation to join project #{#project.business_name}),
:from => %("App" <no-reply#appname.com>),
:to => #user.account.email,
:content_type => "text/html" ) do |format|
format.text
format.html
end
end

Automatic form submission with PERL - debugging!

Our client has a simple setup.
Page A has a form that submits to page B which displays the query results. Unfortunately, there is no other API or DB access to get the data.
Since we need to do this query often, we decided to automate this submission with Perl.
I've determined the form key value pairs of Page A with a sniffer and replicated the code. However, on running the program page B is throwing a HTTP 500 error with no additional meaningful explanation.
Any pointers to debug this code? Code in itself is simple:
use strict;
use warnings;
use LWP;
my $browser = LWP::UserAgent->new;
my $url = "targeturl.asp"
my $response = $browser->post( $url,
[
"HisSort" => "1",
"RTsort" => "",
"chkHisRun" => "on",
"chkRTRun" => "on",
"optAdHoc" => "on",
"optHist" => "",
"optServer" => "servername",
"optStatus" => "",
"optWhat" => "H",
"txtEnd" => "",
"txtFields" => "1,0,10,17,11,18,24,19,21,25,1",
"txtHEnd" => "11/3/2010",
"txtHStart" => "11/1/2010",
"txtServer" => "",
"txtStart" => "",
]
);
Note:
I don't have access to the source of page A or page B
Firstly, I suggest looking at WWW::Mechanize which is a friendlier wrapper around LWP. Secondly, if your HTTP client is getting 500 errors, then there should be something more meaningful in the web server error logs. And finally, as Matthew has mentioned, you need to closely examine the request being sent by the browser and work out how it differs from the request that your Perl program is sending.
Team,
This has been resolved.
It eventually turned out that the problem was not with the headers but with the key value pairs I was sending. Page B wasn't doing validations on the fields and was plugging them into a query directly.
I had to try some brute force combinations (by testing with Page A) to get to what exactly page B was expecting.
Thanks to all who volunteered to help.