How can I send a message using Microsoft Graph that would have both, text AND html bodies?
For those finding this message sometime later, pulling your hair out trying to understand why Microsoft didn't make this clear in the documentation, see this post: Can Office 365 REST API send an email with both plain text and HTML body?
I've confirmed this on my end - once the graph API request is made, the Exchange server does, in fact, strip the HTML characters, creates a multipart message (with boundaries) and delivers in the appropriate format.
In my case, I only needed to set the following:
body.contentType = BodyType.HTML;
body.content = myCustomEmailObject.getHtml();
Here's an example of what the raw response (email source) looks like in gmail:
--_000_CO6PR14MB42581EA88B5BE054EFE62113CF449CO6PR14MB4258namp_
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
This is the content
And this is a new line...
--_000_CO6PR14MB42581EA88B5BE054EFE62113CF449CO6PR14MB4258namp_
Content-Type: text/html; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dus-ascii"=
>
</head>
<body>
<b>This is the content</b><br>
And this is a new line...
</body>
</html>
--_000_CO6PR14MB42581EA88B5BE054EFE62113CF449CO6PR14MB4258namp_--
Related
I´m sending emails through a Rails web app using AmazonSes service. I´m sending different types of emails and everything is working fine, but in the next scenario:
The user can write a text like a message with line breaks in a textarea field within a form. This message is stored in our MySQL dababase and sent by email to another user. I have problems with the line breaks, because depending on if I open the email in Gmail webmail or Mac Mail, the break lines are respected or not. I have read a lot of post with similar problem and tried but unfortunately I couldn´t fix it.
As mentioned, I´m using Rails Mailer to send the emails through AmazonSES services.
Input textarea with message:
This is what I store from the textarea field in database: "messagePreOffer"=>"This is paragraph 2.\n\nThis is paragraph 2.\n\nThis is paragraph 3."
Before rendering the mail template the messagePreOffer log shows:
offer.message_pre_offer=This is paragraph 1.
This is paragraph 2.
This is paragraph 3.
Simplified mail template layout:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<!-- NAME: 1:2 COLUMN -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<p><%= #offer.message_pre_offer %></p>
</body>
</html>
We send the email with mailer (I think this is not relevant):
mail(from: APP_CONFIG['EMAIL_FROM'], to: offer.email, bcc: APP_CONFIG['EMAIL_FROM'], subject: t('new_offer_user_subject', departure: #offer.enquire.departure))
Mailer delivery configuration:
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
:address => "email-smtp.eu-west-1.amazonaws.com",
:port => 587,
...
:authentication => :login,
:enable_starttls_auto => true
}
TEST 1:
This is the log that I got after running and sending the email:
Rendering email_service/send_new_offer_user_notification.html.erb within layouts/email_service
Rendered email_service/send_new_offer_user_notification.html.erb within layouts/email_service (2.0ms)
EmailService#send_new_offer_user_notification: processed outbound mail in 75.5ms
Sent mail to *****#gmail.com (1117.1ms)
Date: Wed, 16 Dec 2020 17:56:23 +0100
From: *******
To: *****#gmail.com
Message-ID: <5fda3c373232d_42433fc7916a717c9102b#MacBook-Pro-****.local.mail>
Subject: Whatever
Mime-Version: 1.0
Content-Type: multipart/alternative;
boundary="--==_mimepart_5fda3c3731200_42433fc7916a717c909a4";
charset=UTF-8
Content-Transfer-Encoding: 7bit
----==_mimepart_5fda3c3731200_42433fc7916a717c909a4
Content-Type: text/plain;
**charset=UTF-8
Content-Transfer-Encoding: 7bit**
This is paragraph 1.
This is paragraph 2.
This is paragraph 3.
----==_mimepart_5fda3c3731200_42433fc7916a717c909a4
Content-Type: text/html;
**charset=UTF-8
Content-Transfer-Encoding: 7bit**
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml">
<head>
<!-- NAME: 1:2 COLUMN -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<p>This is paragraph 1.
This is paragraph 2.
This is paragraph 3.</p>
</body>
</html>
----==_mimepart_5fda3c3731200_42433fc7916a717c909a4--
With this initial configuration, I get the next results:
Result 1: Same result in Gmail and Mac Mail.
I understand this is right, because I didn´t add any format.
TEST 2:
While making tests to write this post I went one step further. My second test just added the next css, to keep line breaks:
<p style="white-space: pre-line;"><%= #offer.message_pre_offer %></p>
After running the test, I got very surprises that it worked perfectly in both Gmail webmail and Mac mail. Find screen here:
TEST 3:
The lines used in the previous test where just for testing purposes. As the tests worked, I tried to use the real text template in spanish. Surprisingly the test didn´t work.
This is the variable log:
"messagePreOffer"=>"Este es el párrafo 1.\n\nEste es el párrafo 2.\n\nEste es el párrafo 3."
This is the log that I got after running and sending the email:
Sent mail to ***#gmail.com (1130.8ms)
Date: Wed, 16 Dec 2020 18:53:23 +0100
From: *****
To: *****
Message-ID: <5fda499338a0f_42433fc7916a717c946d1#MacBook-Pro-de-******.local.mail>
Subject: Whatever
Mime-Version: 1.0
Content-Type: multipart/alternative;
boundary="--==_mimepart_5fda49933789a_42433fc7916a717c945df";
charset=UTF-8
Content-Transfer-Encoding: 7bit
----==_mimepart_5fda49933789a_42433fc7916a717c945df
Content-Type: text/plain;
charset=UTF-8
**Content-Transfer-Encoding: quoted-printable**
Este es el p=C3=A1rrafo 1.=0D
=0D
Este es el p=C3=A1rrafo 2.=0D
=0D
Este es el p=C3=A1rrafo 3.=
----==_mimepart_5fda49933789a_42433fc7916a717c945df
Content-Type: text/html;
charset=UTF-8
**Content-Transfer-Encoding: quoted-printable**
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.o=
rg/TR/xhtml1/DTD/xhtml1-strict.dtd">=0D
<html xmlns=3D"http://www.w3.org/1999/xhtml" xmlns=3D"http://www.w3.org/1=
999/xhtml">=0D
<head>=0D
<!-- NAME: 1:2 COLUMN -->=0D
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3DUTF-8" =
/>=0D
<meta name=3D"viewport" content=3D"width=3Ddevice-width, initial-scale=3D=
1.0" />=0D
</head>=0D
<body>=0D
<p style=3D"white-space: pre-line;">Este es el p=C3=A1rrafo 1.=0D
=0D
Este es el p=C3=A1rrafo 2.=0D
=0D
Este es el p=C3=A1rrafo 3.</p>=0D
</body>=0D
</html>=0D
----==_mimepart_5fda49933789a_42433fc7916a717c945df--
Then in Mail Mac the format is still ok:
However, in Gmail webmail the break lines are broken, with many lines and much more space:
After some tests with the content text, I have found out that the problem starts with the accents. If you take a deep look into the logs, in the first test the charset is:
charset=UTF-8
Content-Transfer-Encoding: 7bit
However, as soon as I include an accent in my text, the content transfer encoding automatically changes to:
charset=UTF-8
**Content-Transfer-Encoding: quoted-printable**
This is the root cause why the break lines are broken. Actually, If I just remove the accent, everything works in Gmail again:
Now, I found the root cause of the problem, but I´m stuck figuring out which is the right solution.
After much more investigation I found this other interesting post: Why isn't Gmail using quoted-printable encoding?
that pointed me that Gmail is not working with quoted-printable. So, I have fixed the problem by forcing the mailer to use 7-bit transfer enconding, with next line in my mailer:
default 'Content-Transfer-Encoding' => '7bit'
I was facing the same issue even with default content_transfer_encoding: 7bit
Rails was still encoding my mail with quoted-printable when ever replying email with large html message.
After spending a day, found this solution working:
mail(
to: ...,
subject: ...,
content_type: 'text/html',
) do |format|
format.html(content_transfer_encoding: 'base64') { Base64.encode64(#mail_box.message) }
end
#mail_box.message is the html contents supplied from a rich text editor. Hope this helps someone.
I am using the Microsoft Graph API to programmatically add content to a OneNote Page on my Office365 OneNote Notebook. For an example page like this:
OneNote snip consisting of Title & 2 separate divs/blocks, this is the generated HTML that I get by making a GET to the pages/{myPageID}/content?includeids=true endpoint
<html lang="en-US">
<head>
<title>Thursday, December 6, 2018</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="created" content="2018-12-06T19:55:00.0000000" />
</head>
<body data-absolute-enabled="true" style="font-family:Calibri;font-size:11pt">
<div id="div:{95790d05-168a-4f61-81a7-5c13e3124069}{4}" style="position:absolute;left:48px;top:115px;width:624px">
<p id="p:{95790d05-168a-4f61-81a7-5c13e3124069}{10}" style="margin-top:0pt;margin-bottom:0pt">It is a jolly good day</p>
</div>
<div id="div:{3a6b78e9-2af8-4a5b-abf8-09871fb6eec5}{20}" style="position:absolute;left:44px;top:180px;width:624px">
<p id="p:{3a6b78e9-2af8-4a5b-abf8-09871fb6eec5}{24}" style="margin-top:0pt;margin-bottom:0pt">Lets do this shall we</p>
</div>
</body>
</html>
I now try adding a new div/block by making the following PATCH using the requests library in Python. The myPageID and access_token are collected previously by making GET requests to the graph API:
patchPageURL='https://graph.microsoft.com/v1.0/users/'+userID+'/onenote/pages/'+myPageID+'/content?includeIDs=true'
patchPageHeaders={
'Content-Type':'application/json',
'Authorization':'Bearer '+access_token
}
patchPageBody=[{
'target':'div:{3a6b78e9-2af8-4a5b-abf8-09871fb6eec5}{20}',
'action':'insert',
'position':'after',
'content':'<div><p> And God said let there be new blocks </p></div>'
}]
patchResp = requests.patch(patchPageURL, headers=patchPageHeaders, json=patchPageBody)
However, I end up with a 400 error as a response to my PATCH request with the following code and message:
code: 20135
message: The entity type is not supported for this operation.
If I change the opening div tag for the content to something like <div data-id="new-div">, I still receive the same 400 error, code 20135.
I am following the instructions from this documentation here. What subtlety is being missed here? There are no authentication or other similar errors. The PATCH works fine if I change the target to body and the action to append but that doesn't make a new div/block and only adds the content as a child of the first div in the page.
Is there a straightforward way to add new blocks/divs as a sibling of existing blocks or even just something as simple as adding a new block at the end of the OneNote page?
We are trying to send html email via MVC postal nuget package. The problem is some clients are seeing raw html tags in the email. Sending the same email to gmail and a few other providers causes no issues. Any ideas?
We are following the simple conventions as per the docs.
Email.cshtml
#model InviteViewModel
To: #Model.Email
From: invites#domain.com
Subject: #Model.Subject
Views: Html
Email.Html.cshtml
#model InviteViewModel
Content-Type: text/html; charset=utf-8
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
bla blah......
</html>
The Content-Type: text/html; charset=utf-8 of the *.Html.cshtml file must be at the topmost line of the file.
Email.Html.cshtml
Content-Type: text/html; charset=utf-8
#model InviteViewModel
<html>
bla blah......
</html>
I recently discovered rails streaming, and having read the various documentation, I tried to add it to one of my controllers like so:
def index
render :stream => true
end
My template file currently looks like this:
<%10.times do%>
<p>
I should get streamed ERB...
<%sleep 0.5%>
</p>
<%end%>
But instead of displaying a message every 0.5 seconds, it waits 5 seconds and displays the whole page! I have checked this behavior in a browser and using curl.
I am using unicorn on OSX, and yes, I configured unicorn.rb for streaming:
listen 3000, :tcp_nodelay => true, :tcp_nopush => false
worker_processes 1
If you want to see my layout file, it looks like this:
<!DOCTYPE html>
<html>
<head>
<title>StreamingTest</title>
<%= stylesheet_link_tag "application" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
I tried disabling all gems (except rails and postgres), and I pared my controller, layout, and template down to the bare minimum, without any success.
I even went so far as to download a complete streaming demo I found (https://github.com/slim-template/slim-streamingtest), and when I ran that, it didn't stream either! (Note to anybody trying to run that demo: I had to change the gemfile source to use https instead of http before I could "bundle install", and I had to "bundle update sprockets" before it would run)
I note that somebody else (using Puma) appears to have a similar problem, which has not been successfully resolved:
Rails Streaming not Streaming
It may be that whatever works for me will also work for them.
Streaming would really help our app, if I could just get it to work, but I can't even get demo streaming apps to run correctly! I suspect it might have something to do with my dev environment, but the problem remains when I deploy my app to Heroku, and I'm out of ideas. Any help would be greatly appreciated . . .
Thanks!
I tried the demo repo you mentioned and the behaviour is as expected. In the example you show it will stop streaming the template, then wait for it to be fully rendered after 5 sec and send the rest. If you use curl:
# curl -i http://localhost:3000
HTTP/1.1 200 OK
Date: Thu, 21 Apr 2016 17:29:00 GMT
Connection: close
Cache-Control: no-cache
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
X-UA-Compatible: IE=Edge
X-Runtime: 0.018132
<!DOCTYPE html>
<html>
<head>
<title>StreamingTest</title>
<link href="/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
<script src="/javascripts/application.js" type="text/javascript"></script>
<meta content="authenticity_token" name="csrf-param" />
Then it waits for 5 seconds for the template to finish its rendering and then sends it.
...
<p>
I should get streamed...
</p>
</body></html>
That's what's supposed to happen. It will not send a part of the partial every 0,5 seconds.
The main goal of streaming with templates is for the browser to receive the headers before the rest of the content so that it makes it possible to save some time in loading assets. As stated in the docs.
Streaming inverts the rendering flow by rendering the layout first and streaming each part of the layout as they are processed. This allows the header of the HTML (which is usually in the layout) to be streamed back to client very quickly, allowing JavaScripts and stylesheets to be loaded earlier than usual.
It's not going to send the partial unless it's been fully rendered.
However, to show you how to get the kind of behaviour you're expecting you could change the body of application.html.slim layout like this:
body
= yield
= render 'application/other'
And create a partial named _other.html.erb with the following content
<% sleep 1 %>
<p>Me too!</p>
And now you'll see in curl that it renders the beginning of the layout, waits for the rendering to be finished on index.html.erb, sends it and shows up in curl and then waits for the _other.html.erb partial to be finished rendering to end the request body. Voilà.
You could also directly feed the request body, to send content every few milliseconds, you can do the following:
def index
headers['Cache-Control'] = 'no-cache'
self.response_body = Enumerator.new do |yielder|
10.times do
yielder << "I should be streamed...\n"
sleep 0.3
end
end
end
This is however not meant to send html, although you could by using render_to_string but then you'll have to modify quite a lot in your code.
Note that all this is Rails 3.x, for 4.x you'll have to use ActionController::Live. In the case of ActionController::Live, there are examples on how to listen to the server sent events in js to render client side such as this mini-chat.
I have a simple Google maps web application I'm working on. I have purchased a domain name for the application (http://www.jcunav.com), which during my testing, is designed to simply forward to a page which is hosted on my another domain name of mine (http://www.codeemporium.com/experiments/map5.html). Testing on my Android Nexus S, I am noticing strange behaviour however - if I visit http://www.codeemporium.com/experiments/map5.html directly, then the app displays as intended - the map is the size I want and clicking the "About" link brings up a dialog the size I want. If I visit http://www.jcunav.com however (which, keep in mind, simply forwards to http://www.codeemporium.com/experiments/map5.html), the map displays at what looks like a more zoomed out level, and pressing the "About" link at the bottom of the page shows a dialog box which also appears more zoomed out. My question is, what could be causing this to occur, given that all http://www.jcunav.com is doing is forwarding to http://www.codeemporium.com/experiments/map5.html...
Are you certain you aren't frame-forwarding? I examined the page in firebug for each of the links you provided and it appears to me that you are frame-forwarding the URL. This results in your target page being 'wrapped' in a frame when presented to the end user. Odds are high that this is why it is not working for you.
Here is a somewhat lossy version of what is in the forwarded page:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"
"http://www.w3.org/TR/html4/frameset.dtd">
<html>
<head>
<title>JCU Nav</title>
<META NAME="Keywords" CONTENT="">
<META NAME="Description" CONTENT="">
</head>
<frameset frameborder="0" framespacing="0" border="0" rows="100%,*">
<frame name="MYTOPFRAME" src="http://www.codeemporium.com/experiments/map5.html" noresize>
-- snip --
</frameset>
</html>
Notice the frame tag:
<frameset frameborder="0" framespacing="0" border="0" rows="100%,*">
<frame name="MYTOPFRAME" src="http://www.codeemporium.com/experiments/map5.html" noresize>
This is what happens when you frame forward.
Since your sizing relies on additions to the HTML tag:
<html class="ui-mobile landscape min-width-320px min-width-480px min-width-768px min-width-1024px">
They do not work in the frame-forwarded version because they are nested inside the frame and not on the root page.
That's because http://www.jcunav.com is not forwarding to http://www.codeemporium.com/experiments/map5.html, it is loading it into a frame:
C:\Documents and Settings\blah>wget -S -O - http://www.jcunav.com/
--01:05:21-- http://www.jcunav.com/
=> `-'
Resolving www.jcunav.com... 66.150.161.141, 69.25.27.173, 63.251.171.80, ...
Connecting to www.jcunav.com|66.150.161.141|:80... connected.
HTTP request sent, awaiting response...
HTTP/1.1 200 OK
Date: Sun, 01 May 2011 05:01:11 GMT
Server: Apache/2.0.49 (Unix) PHP/4.3.9
X-Powered-By: PHP/4.3.9
Content-Length: 823
Connection: close
Content-Type: text/html; charset=ISO-8859-1
Length: 823 [text/html]
0% [ ] 0 --.--K/s <
!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"
"http://www.w3.org/TR/html4/frameset.dtd">
<html>
<head>
<title>JCU Nav</title>
<META NAME="Keywords" CONTENT="">
<META NAME="Description" CONTENT="">
</head>
<frameset frameborder="0" framespacing="0" border="0" rows="100%,*">
<frame name="MYTOPFRAME" src="http://www.codeemporium.com/experiments/map5.html" noresize>
<noframes>
<body>
<h1>JCU Nav</h1>
<br>
<br>
<br>
Click here to enter <a href="http://www.codeemporium.com/experiments/map5.html">http://www.codeemporium.com/e
xperiments/map5.html</a>
<hr>
| Domain Name Registration and Domain Name Forwarding by <a href="http://www.mydomain.com">mydomain.com - Register your
domain name</a>
</body>
</noframes>
</frameset>
</html>
You'll need to actually change that frame set to do the right thing.