If using Windows Live Writer or Microsoft Word 2007 to create blog posts in Windows SharePoint Services (WSS) 3.0 it appears, at least on our installation of SharePoint, that when you embed new images in the post, the image tags are generated with relative links, e.g. <img src="/Lists/Posts/Attachments/51/image_thumb.png"> . This is fine if you're viewing the feeds in a web browser as it can resolve the server name for the links from the feed address. But if you're using Outlook 2007 to subscribe to the feeds, any images you embedded in the post using Live Writer or Word are generated as relative links, Outlook can't/doesn't resolve the site name hence the images are broken:


Whose fault this is (Outlook/SharePoint/Live Writer) I don't know, but fixing it required a bit of coding hackery - I couldn't find any option in the SharePoint configuration for controlling the generation of RSS.

WSS v3.0's default RSS generator is a page called ListFeed.aspx that lives in Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\template\layouts. By default it looks like this:

<%@ Assembly Name="Microsoft.SharePoint.ApplicationPages" %>
<%@ Page Language="C#" Inherits="Microsoft.SharePoint.ApplicationPages.ListFeed" %> 

Clearly all the logic is in Microsoft.SharePoint.ApplicationPages.dll. So to fix this, I backed up this file and added the following code to ListFeed.aspx which basically passes all of the feed content through a filter using HttpResponse.Filter which uses a regular expression to replaces any relative <img src="/blah"> tags with the absolute <img src="http://site/blah">.

<%@ Assembly Name="Microsoft.SharePoint.ApplicationPages" %>
<%@ Page Language="C#" Inherits="Microsoft.SharePoint.ApplicationPages.ListFeed" %>
<script language="C#" runat="server">
protected override void OnInit(EventArgs e)
  base.Response.Filter = new RelativePathFilter(base.Response.Filter, this.Request, this.Response);

class RelativePathFilter : System.IO.Stream { System.IO.Stream _innerStream; string _siteUrl; Regex _imagesRegex; HttpResponse _response;

public RelativePathFilter(System.IO.Stream innerStream, HttpRequest request, HttpResponse response) { _innerStream = innerStream; _siteUrl = (new Uri(request.Url, HttpRuntime.AppDomainAppVirtualPath)).AbsoluteUri; _response = response;

// Finds rooted images &lt;img ... src="/ ...
_imagesRegex = new Regex(@"(&lt;img .*? \s src \s* = \s* [""']?)/", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);


public override void Write(byte[] buffer, int offset, int count) { string content = _response.ContentEncoding.GetString(buffer, offset, count);

// Ignore the fact that it's theoretically possible for the &lt;img&gt; tag to be split between 2 Write()s
content = _imagesRegex.Replace(content, @"$1" + _siteUrl);

byte[] newBuffer = _response.ContentEncoding.GetBytes(content);
_innerStream.Write(newBuffer, 0, newBuffer.Length);


public override bool CanRead { get { return _innerStream.CanRead; } } public override bool CanSeek { get { return _innerStream.CanSeek; } } public override bool CanWrite { get { return _innerStream.CanWrite; } } public override void Flush() { _innerStream.Flush(); } public override long Length { get { return _innerStream.Length; } } public override long Position { get { return _innerStream.Position; } set { _innerStream.Position = value; } } public override int Read(byte[] buffer, int offset, int count) { return _innerStream.Read(buffer, offset, count); } public override long Seek(long offset, System.IO.SeekOrigin origin) { return _innerStream.Seek(offset, origin); } public override void SetLength(long value) { _innerStream.SetLength(value); } } </script>

I'm not entirely sure whether hacking around with these files is supported (although it did seem to survive the installation of WSS 3.0 SP1), or if there's a better way of doing this, so use at your own risk.

Update 22 April 2008: Modified code so that it doesn't assume the site is at the root of a virtual server.


Comment by Russ

I tried your solution and it just broke my RSS feads. I had to put the origional code back.

I am having the same problem you saw, and I just have no idea where to go next.

Comment by Russ

Okay, scratch my last. Text encoding makes all the difference.

My RSS feed is no longer crashing, but it doesn't seem to be fixing the image links. I guess this is the right path, ( wish there was a native setting ), so I just need to play with it.

Comment by duncansmart

Russ, I think the issue was that my code originally assumed that the SharePoint site was at the root of a server. The updated code *should* do the trick.

Comment by Michael Stum

Many Thanks for that! Just as a heads-up: ListFeed.aspx is hard-coded within Sharepoint, so the only way to avoid having to modify that file is to set up some URL Rewriting stuff in IIS that turns ListFeed.aspx to somethingelse.aspx.

Comment by René Hézser

great solution!
I've adjusted the Regex, so that a regular link will be "absoluted" as well.
new Regex:
_imagesRegex = new Regex(@"(<img .*? \s src \s* = \s* [""']?)/|(<a .*? \s href \s* = \s* [""']?)/", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);


Comment by René Hézser

Hmm. This is not working. Can somebody assist here?

Comment by duncansmart

Rene - this Regex is what you're after I think:

_imagesRegex = new Regex(@"(< (img|a) .*? \s (src|href) \s* = \s* [""']?)/", ...);

(You may need to change the curly quotes that WordPress insists on putting in, to normal ones)

Comment by René Hézser

Hi Duncan,
cool. thx. This one is working :-)


Comment by Davis

This may be out of the topic but maybe you could help me on this.

I've created a webpart through code and I wanted to add/embed it directly on the page. Could you help me on how to do this?

Comment by Duncan Smart

@Davis: sorry I'm just an ASP.NET guy - not a SharePoint one!

Duncan Smart
Comment by Philip Colmer

Just wanted to share that this appears to happen with normal blog postings as well. I've taken a "broken" Word blog posting, copied it into Notepad, made sure the URLs are fully qualified and then created a new blog posting from that Notepad text. The URLs become relative in the RSS feed.

I've even just created a posting that pulls in an image using the SharePoint interface and the RSS feed does the same thing.

If this isn't happening to everyone, something that might be a common factor is the installation of the community blog extensions? I haven't done enough testing to see if a truly out-of-the-box SharePoint behaves in the same way.

Philip Colmer
Comment by Tuesday

So, what you are all saying in general is that the RSS Listfeed.aspx file is not easily modifiable w/out adding custom funtions, etc.? :)

Comment by Jack

Very good information about breaking the images during modifying the software, I have never see the information like it.I will careful in future concern it.

Comment by 7echno7im

Hi, good info. Anyone know of a way to post from Word to SharePoint BUT include embedded images as Live Writer does. Live writer is able to post content with images without checking int he imagages. Word seems to lack this. Is there any way to trick Word to post like Live Writer?

Comment by Marius Botha

Need some help: Anybody else come across the following problem: When blogging to SharePoint from Word, and I edit an existing post, and add a new image. It replaces an existing image on the post (in Photos Library). Its like Word does not realise that there are already images posted. The problem is probably because when Word submits the new image, it still uses the blog post create date as part of the new image filename. Any ideas?

Comment by Matt@Tier1Support

Killer post. Thanks for sharing. This also will work for the built in feed reader for lotus notes.