Using MSO- styles in Email
If you’ve been working in email dev, you may have come across mso-
prefixed styles in the code, I mention them a few time on this site. MSO styles are styles that are specific to MSO (MicroSoft Office), some of these styles are unique to MSO but often these are repeats of standard CSS styles, in which case they can be used to provide a different value in MSO email clients.
The MSO email clients include Outlook desktop app on Windows, and Windows Mail the rendering of these apps is based on Microsoft Word. Other versions of Outlook, such as the Mac app, Android app, iOS app, the webmail and Progressive Web Apps (PWA) use regular HTML rendering and don’t support these MSO styles.
There are a lot of MSO prefixed styles as documented in this great resource, Stig’s MSO reference page. Stig got this recourse from Jason who shared a Microsoft Office HTML and XML Reference PDF that he in turn downloaded and decoded from this Microsoft® Office HTML and XML Reference. This is one of the things I love about the email community, people are happy to share their findings and expand on each other’s work.
Over the years, I’ve gone through this document and a few others and made some notes about which of these style work in Outlook and how to use them.
There is quite a lot to cover, so I’ve broken it down into a few sections to hopefully make things easier to follow
- MSO text styling
- MSO advanced text styling (Word Art)
- MSO box model
- MSO backgrounds
- MSO table styles
- MSO List styles
- MSO element
- more to follow…
MSO text styling
There are a few different font types used here ascii, ansi, bidi, fareast, hansi, symbol. Depending on what language you’re sending in ,you may need to adjust some of these styles accordingly (I need to do more testing around this). For now I’m focusing on English content, so looking at ascii and ansi.
mso-ansi-font-size
Works in a similar way to font-size
. Additionally, it will accept a unitless font (mso-ansi-font-size:30
) and treat is as 30px
<p style="mso-ansi-font-size:30px">test</p>
mso-ansi-font-style
Works just like font-style
<p style="mso-ansi-font-style:italic">test</p>
mso-ansi-font-weight
Works just like font-weight
<p style="mso-ansi-font-weight:bold">test</p>
mso-ansi-language
This can be used to define a language, Outlook will pass this value onto a lang=""
attribute.
<p style="mso-ansi-language: es">prueba</p>
mso-ascii-font-family
Works just like font-family
<p style="mso-ascii-font-family:Arial, sans-serif">test</p>
mso-generic-font-family & mso-font-alt
These don’t appear to work in the majority of places however, they can be used as part of a fallback for webfonts, Read more about web font fallback with mso-generic-font-family on hteumeuleu.com
mso-font-width
This works a bit like transform:scaleX()
but is only applied to the text and unlike transform
this does affect the flow of the DOM.
It is set as a %
where 100% is the default value.
<p style="mso-font-width:50%">test</p>
mso-color-alt / mso-style-textfill-fill-color
Both work just like color
<p style="mso-color-alt:#ff0000">test</p>
<p style="mso-style-textfill-fill-color:#ff0000">test</p>
mso-line-height-alt
Works just like line-height
. When using unitless values they need to be whole numbers and not decimals. If you want a line height of1.5
you can use 150%
or 1.5em
.
<p style="mso-line-height-alt:150%">test</p>
mso-line-height-rule
This is a modifier for line-height
to say if the rule should be applied exactly
or at-least
. It’s only applies to fixed unit values like px
and uses at-least
as the default value.
When using relative units like %
this is not needed and line-height
will work as expected.
It’s only needed if you have a very small line height, set with a fixed unit.
<p style="mso-line-height-alt:10px; mso-line-height-rule:exactly;">test</p>
mso-style-textfill-fill-alpha
Works like opacity
but only works on text and only accepts % values.
<p style="mso-style-textfill-fill-alpha:50%;">test</p>
mso-style-textfill-type: none
Similar to color:transparent
MSO email clients don’t respect the transparent
keyword so this can be used as a work around for that.
<p style="mso-style-textfill-type: none">test</p>
Also see mso-style-textfill-type: gradient
mso-text-indent-alt
Works just like text-indent
<p style="mso-text-indent-alt:50px">test</p>
mso-text-raise
Similar to padding-bottom
but also works on inline elements. It can also take a negative value to make it similar to padding-top
<p style="mso-text-raise:50px">test</p>
<p style="mso-text-raise:-50px">test</p>
text-underline-color
Works just like text-decoration-color
<p style="text-decoration:underline; text-underline-color: #FF0000">test</p>
mso-char-indent
Works in a similar way to text-indent
. This is the shorthand version of mso-char-indent-count
(how many characters to indent by) and mso-char-indent-size
(how big those characters are). However the indent size dosn’t work in Outlook so we can only set the count, but this works either as long hand or short hand.
<p style="mso-char-indent: 2">test</p>
<p style="mso-char-indent-count: 2">test</p>
For a closer comparison to text-indent
see mso-text-indent-alt
MSO advanced text styles (Word Art)
Back in the 90’s if you want to create a poster for your school disco, you would do it in MS Word using Word Art. If you’re still loving this retro style then we can recreate it in Outlook too.
mso-effects-shadow
Ok this is a complicated one, it’s similar to text-shadow
but works a little differently.
<p style="mso-effects-shadow-color: #ff0000; mso-effects-shadow-alpha: 100%; mso-effects-shadow-dpiradius: 0pt; mso-effects-shadow-dpidistance: 10pt; mso-effects-shadow-angledirection: 5400000; mso-effects-shadow-pctsx: 100%; mso-effects-shadow-pctsy: 100%;">
test
</p>
So I’ll break that down
mso-effects-shadow-color
set the colour.mso-effects-shadow-alpha
sets the opacity of the shadow.mso-effects-shadow-dpiradius
sets the amount of blur on the .shadow.mso-effects-shadow-dpidistance
sets the distance the shadow is away from the text.mso-effects-shadow-angledirection
This sets the angle of the shadow. The units it uses are 1/60000th of a degree, with 0 being out to the right of the text. So if you want it directly below the text, that’s a 90° degree angle × 60000 = 5400000.mso-effects-shadow-pctsx
sets the scale of the shadow on the X axis.mso-effects-shadow-pctsy
sets the scale of the shadow on the Y axis.
mso-style-textoutline
This is similar to CSS -webkit-text-stroke
which is an experimental feature that’s been sitting in the experimental box for some time. Chris Coyier has a good article on CSS text-stroke
<p style="font-size:50px; mso-style-textoutline-type:solid; mso-style-textoutline-fill-color:red; mso-style-textoutline-outlinestyle-dpiwidth:1pt;">test</p>
I’ll break this down as well
mso-style-textoutline-type
sets our text outline assolid
orgradient
. I’m just focusing on solid for the moment.mso-style-textoutline-fill-color
sets the colour of the outline.mso-style-textoutline-outlinestyle-dpiwidth
sets the thickness of the outline.
Those first 3 are required, but if you want some more options…
mso-style-textoutline-fill-alpha
sets the opacity of the outline.mso-style-textoutline-outlinestyle-dash
sets the outline style a bit likeborder-style
the options aresolid
(default),dotsys
,dashsys
,dashgel
,dashdotgel
,longdashgel
,longdashdotgel
,longdashdotdotgel
mso-style-textoutline-outlinestyle-compound
is also a bit likeborder-style
these options aresimple
(default),double
,tripple
,thickthin
,thinthick
. Also take a look back at mso-style-textfill-fill-alpha as that pairs well with using an outline.
mso-style-textfill-type: gradient;
<p style="mso-style-textfill-type: gradient;
mso-style-textfill-fill-gradientfill-shadetype:linear;
mso-style-textfill-fill-gradientfill-shade-linearshade-angle:
0;mso-style-textfill-fill-gradientfill-stoplist:'0 \#000000 -1 100000\,50000 \#C00000 -1 100000\,100000 \#000000 -1 100000'">
test
</p>
mso-style-textfill-type: gradient;
set this as a gradient fill.mso-style-textfill-fill-gradientfill-shadetype: linear;
sets the type of gradient fill, options arelinear
(default) not sure about other options yet.mso-style-textfill-fill-gradientfill-shade-linearshade-angle: 5400000;
sets the direction of the gradient. Again this uses units of 1/60000th of a degree, with 0 being a left to right gradient.mso-style-textfill-fill-gradientfill-stoplist:"0 \#000000 1 100000\,50000 \#C00000 -1 100000\,100000 \#FFFFFF 0 0
sets the colours of the gradient as a comma separated list.- Each part has a position, set in 1/1000th of a % (so that means 50000 = 50%).
- Then a hex colour escaped with a
\
. - Then a number representing something I don’t understand yet, but may is to do with blending over the underneath color.
-1
seems to do what we need. - Then opacity set in 1/1000th of a %
- Additionally we can also add
lumm=90000 lumo=3000
which I’m assuming stands for Luminance & Luminosity.
MSO Box Model
mso-margin-top-alt, mso-margin-bottom-alt
Works just like margin-top
and margin-bottom
. But doesn’t work with left, right or shorthand values.
<p style="mso-margin-top-alt:1em;mso-margin-bottom-alt:1em;">test</p>
mso-para-margin
Works just like margin
also supports short hand values and longhand mso-para-margin-top
, mso-para-margin-right
, mso-para-margin-bottom
, mso-para-margin-left
.
<p style="mso-para-margin:0 0 3em 5em;">test</p>
mso-padding-alt
Works just like padding
. Also supports longhand values mso-padding-top-alt
, mso-padding-right-alt
, mso-padding-bottom-alt
, mso-padding-left-alt
<p style="mso-padding-top-alt:1em;mso-padding-bottom-alt:1em;background:red;border:1px solid;">test</p>
For padding to work on a <p>
we also need to add a border
.
mso-padding-between
This only works when mso-border-between
is set on a element. It sets the padding the 2 elements that Outlook has joined
<p style="border:4px solid green;mso-border-between:4px dotted pink; mso-padding-between:50px">test</p>
<p style="border:4px solid green;">test</p>
mso-border-alt
Works just like border
. Inline elements like <span>
, <a>
only support a single style which will be applied to all sides. Block elements like <div>
, <table>
support different values on each side.
There is also support for longhand values for sides mso-border-top-alt
, mso-border-right-alt
, mso-border-bottom-alt
, mso-border-left-alt
and for settings mso-border-style-alt
, mso-border-color-alt
, mso-border-width-alt
. On inline elements these will be applied to all 4 sides.
<p style="mso-border-alt:4px solid green">test</p>
mso-border-between
Outlook will sometimes combine block level elements that are adjacent to eachother, which have matching border styles. For example if you have 2 <p>
elements both with a border, you may only see an outer border around both elements and not between them. To fix this we can set a border between them, this could also be set as a different value.
<p style="border:4px solid green; mso-border-between:4px dotted pink;">test</p>
<p style="border:4px solid green;">test</p>
This can be combined with mso-padding-between
This could also be useful on tables
<table style="border:1px solid green;mso-border-between:1px dashed red; mso-padding-between:50px">
<tr>
<td>test1</td><td>test2</td>
</tr>
<tr>
<td>test3</td><td>test4</td>
</tr>
</table>
mso-border-shadow
Similar to box-shadow
but with less control. This only works when a border is set, and the options are just yes
and no
, if yes then a black shadow will be added to the bottom right at the same width as the border.
<p style="border:solid red 8px; mso-border-shadow:yes">test</p>
MSO Backgrounds
mso-shading
Works just like background-color
<p style="mso-shading: red">test</p>
mso-pattern
This adds a simple predefined pattern. This can also take the longhand form mso-pattern-color
and mso-pattern-style
The style options include;
diag-cross
, diag-stripe
, gray-025
, gray-0625
, gray-075
, gray-10
, gray-125
, gray-15
, gray-175
, gray-20
, gray-225
, gray-25
, gray-275
, gray-30
, gray-325
, gray-35
, gray-375
, gray-40
, gray-425
, gray-45
, gray-475
, gray-5
, gray-50
, gray-525
, gray-55
, gray-575
, gray-60
, gray-625
, gray-65
, gray-675
, gray-70
, gray-725
, gray-75
, gray-775
, gray-80
, gray-825
, gray-85
, gray-875
, gray-90
, gray-925
, gray-95
, gray-975
, horz-cross
, horz-stripe
, none
, reverse-diag-stripe
, solid
, thick-diag-cross
, thin-diag-cross
, thin-diag-stripe
, thin-horz-cross
, thin-horz-stripe
, thin-reverse-diag-stripe
, thin-vert-stripe
, vert-stripe
<p style="mso-pattern:vert-stripe red">test</p>
<p style="mso-pattern-color:red; mso-pattern-style: vert-stripe">test</p>
MSO table styles
mso-cellspacing
Works in a similar way to the cellspacing=""
attribute or like the border-spacing
style in CSS. Using mso-cellspacing
mean we can use other units such as em
to improve accessibility which isn’t possible using the cellspacing=""
attribute. The value can also set with a unit, in which case it will be treated as px
.
<table style="mso-cellspacing:1em">
<tr>
<td>test</td>
</tr>
</table>
mso-cell-special
I’m not too sure what this does but using mso-cell-special: placeholder
will remove a <td>
from the DOM.
mso-table-dir
Similar to the dir=""
attribute, this sets the language direction of the table. Values are normal
(left to right), rtl
(right to left), bidi
(bidirectional).
<table style="mso-table-dir:bidi">
<tr>
<td>a</td><td>b</td>
</tr>
</table>
mso-table-tspace
These are similar to margin-top
but only when the table is floated with an align="left"
or align="right"
attribute.
<table style="mso-table-tspace:50px;" align="left">
<tr>
<td>test</td>
</tr>
</table>
mso-table-lspace
These are similar to margin-left
but only when the table is floated with an align="left"
or align="right"
attribute.
<table style="mso-table-lspace:50px;" align="left">
<tr>
<td>test</td>
</tr>
</table>
mso-table-rspace
These are similar to margin-right
but only when the table is floated with an align="left"
or align="right"
attribute.
<table style="mso-table-rspace:50px;" align="left">
<tr>
<td>test</td>
</tr>
</table>
mso-table-bspace
These are similar to margin-bottom
but only when the table is floated with an align="left"
or align="right"
attribute.
<table style="mso-table-bspace:50px;" align="left">
<tr>
<td>test</td>
</tr>
</table>
MSO List styles
mso-special-format
When adding a left margin to lists <ul>
or <ol>
, Outlook likes to convert the <li>
elements into <p>
elements and will mess with the spacing. This is flipped in rtl
languages to the right margin.
We can work around this by adding mso-special-format:bullet;
<ul style="margin-left:10px;" >
<li style="mso-special-format:bullet;">Test</li>
<li style="mso-special-format:bullet;">Test</li>
<li style="mso-special-format:bullet;">Test</li>
</ul>
However this will also reset to the default margin (about 48px in Outlook) and default list-style-type: disc;
mso-bullet-image
Works similar to list-style-image
but only accepts gif
and ico
formats. Also it requires setting mso-special-format:bullet
<ul>
<li style="mso-special-format:bullet;mso-bullet-image:'https://dummyimage.com/600x400/fff/000.gif&text=✓'">
test
</li>
</ul>
If you want to remove a list icon to replicate, list-style: none
you could use a transparent gif as the mso-bullet-image
.
MSO element
When using mso-elements you’ll see a border appear around the first element used. I’ve not worked out how to remove this yet but we can set another element first that will take the boarder then move that out of the way.
Place this code at the top of your email
<div style="mso-element-wrap:none;mso-element-left:right;font-size:1px;">‌</div>
You will still see it in the top right corner but this is the best I have so far.
mso-element
This is used to set an element. In it doesn’t do much on it’s own. However be aware that setting a valuse of none
will remove all the content after it.
<div style="mso-element:none"></div>
So don’t do that.
mso-element-frame-width
Set the width of the mso-element. There is no need to a set mso-element: frame
, In Outlook the rendered code becomes a <table>
<div style="mso-element-frame-width:600px;">test</div>
mso-element-frame-height
Set the height of the mso-element. There is no need to a set mso-element: frame
, In Outlook the rendered code becomes a <table>
<div style="mso-element-frame-height:400px;">test</div>
mso-element-wrap
This sets the wrapping of the mso-element, it works a bit like CSS float
- around works like float, other elements will wrap around it
- auto Sets to around
- none works like position, absolute and takes the element out of the flow of the DOM
- no-wrap-beside similar to display:block puts the element on it’s own line
Here’s an example of it used for a drop-cap on a paragraph.
<div style="font-size:48px; mso-element-wrap:around;">L</div>
<p>orem ipsum dolor sit amet, consectetur adipiscing elit.<br>
Aenean tincidunt, diam a rutrum tristique, tellus turpis malesuada enim, sed luctus est turpis quis sem.<br>
Ut tellus augue, pulvinar ac nunc iaculis, interdum tristique orci.<br>
Curabitur maximus lacus erat, vitae rutrum tortor ullamcorper in.</p>
mso-element-left
Positioning from the left, similar to margin-left
- center acts like
margin:0 auto;
and centres the element. This only works whenmso-element-wrap:no-wrap-beside;
is set. - [length] sets a value with units (
mso-element-left:50px
). Acts likemargin-left
. This only works whenmso-element-wrap:no-wrap-beside;
is set. - left/right Acts like
float:left
float:right
- inside/outside Appears to do the same as left/right
There is also mso-element-top
but I’ve not get ot working yet
mso-element-frame-vspace
Works like css margin-block
to give vertical space. This requires setting a mso-element-frame-height
, mso-element-frame-width
or mso-element-wrap
to make the vspace work.
<div style="mso-element-wrap:no-wrap-beside;mso-element-frame-vspace:20px;">test</div>
mso-element-frame-hspace
Works like css margin-inline
to give horazontal space. This requires setting a mso-element-frame-height
, mso-element-frame-width
or mso-element-wrap
to make the hspace work.
<div style="mso-element-wrap:no-wrap-beside;mso-element-frame-hspace:20px;">test</div>
More to come
I’ve had this half finished for a few months and very slowly adding to it, but I’ve already referenced it a few times so I decided I’ll put it live and finish it off when I get time.