Showing posts with label Tips Tricks. Show all posts
Showing posts with label Tips Tricks. Show all posts

Thursday, 7 December 2017

Angular2 - Material Autocomplete and remote filtering data

Problem:

The last couple of days I was struggling to get the Angular2 Material Autocomplete to work with our api. I wanted the autocomplete options remotely filtered. Several solutions I found, worked with a (cached) list of items. So all items were first retrieved and after that, those were filtered by the autocomplete. This is ok if the full list is a short list, but not for long(er) lists.
Well, after searching and trying a lot, and for a long time (also together with my colleague Frank den Outer, special thanks to him!) and struggling with promises and observables, we found the solution and it is actually really simple (at least, it looks like that).

The data is coming from an server api and is accessed by the function getCompanies(search: string) from a company.service.ts (which is injected in the user component). This function returns an Observable.

Solution


On the user.component.html I used:












On the related user.component.ts, you the following pieces of code:



The 'debounceTime(300)' is used to prevent a api-call on each keyup event.
In our case, if no value is entered in the input box, the api returns the first 20 entries of the list of companies.
The main difference with other solutions (where a (cached) list on client side is used) is the .subscribe() part. In other solutions you will find a .map call, something like this:


where allCompanies is a fetched list with all companies. This .map function will not respond correctly with the customSearchFunction if the result is retrieved directly from a api.

But I really prefer the 'subscribe' solution, because you get directly your data filtered from you api and you don't need to preload all data and store it local. And it is less code as well ;)

Happy programming!

Tuesday, 31 January 2017

ASP.NET MVC $.ajax error handling

Problem:
I tried inside my (classic) MVC web application to show custom error(message)s when using $.ajax(). Several options tried, like:
return new HttpStatusCodeResult(401, "Custom Error Message 1");
but no luck. On some weird way, the error was not cached inside my $.ajax().error(...)

Solution:
I wrote a custom extension method on Controller level:
public static class ControllerExtensions
{
 public static ContentResult CustomError(this Controller ctl, int statuscode, string message)
 {
  ctl.Response.ContentType = "application/json";
  ctl.Response.StatusCode = statuscode;
  ctl.Response.Write(message);
  return new ContentResult();
 }
}

So, inside my controller actions, I can just call:
 return this.CustomError(400, myerrormessage);

On the view I now can just do the following:
$.ajax({
 // do you stuff here
 success: function (response) {
  // do success response actions
 },
 error: function (data, textStatus, jqXHR) {
  // the 'data' contains data.responseText, which is the 'myerrormessage' entered into the extension method
  // 'data' contains data.status, which is the statuscode entered into the extension method (400)
  toastr["error"]("Error(s) during loading group list:
" + data.responseText);
 }


Well, that's it for me. It might be useful for you :)

Thursday, 8 December 2016

NHibernate.StaleStateException : Unexpected row count

Situation:
Console application with NHibernate and a MySQL database. The application read several (large) files with data and process it to the database. For several reasons, all entries that are read from the files needs to be compared with existing entries in the database. New one's should be added, existing entries should be updated (if needed) and entries that does not exist anymore in the import files needs to be update (property set to inactive = true). So far so good.

Problem:
I ran several times into the NHibernate.StaleStateException with the unexpected row count message.
I changed from session.save() and session.flush() to a transaction with commit way of dealing with the objects. I also started to use Parallel.ForEach when processing the read entries for performance reasons. During testing (with smaller files) everything went well. Till I started to read files from over 15Mb (I got even files of > 60Mb). That was the moment that those NHibernate.StaleStateException's were fired.

Solution:
After searching a lot and reading a lot of flushing, saves, transactions and versions I still got not the correct answer for my problem.
However, I've found the solution. It was not really an Nhibernate issue, but a MySQL issue. I had to change a few database parameters:
  • innodb_buffer_pool_size. I changed the default value of 8M to 512M. This speed up the entire process a lot. On production server(s) this value can be set higher as well (depending on the available RAM of the machine).
  • innodb_log_file_size. I changed this one to 128M
  • max_allowed_packet. If this value is to small, NHibernate will fire those StaleStateExceptions if you are processing such amount of data(files). So I changed it to 100M
Those parameter you can find in the my.ini file of MySQL (location of my file is at C:\ProgramData\MySQL\MySQL Server 5.7\my.ini). More info of those parameters can be found in the my.ini file.
After changing those parameters, you need to restart the MySQL service.

For me, those 3 db-parameters did the trick.

Monday, 18 July 2016

Tilde key not working in VMware fusion

Problem:

Today I ran into a small but frustrating problem. The tilde key (~) didn’t work on my VMware fusion machine.

Situation:

I run Windows 10 in VMware fusion on a Macbook Pro. I searched a bit around the internet but didn’t find the right solution. By the way, my keyboard layout is US, so the ‘~’ key should be on the key just left from the ‘1’.
Some trial and error with keyboard combination with CTRL, ALT, Winkey etc didn’t work out. Strangely enough, I got it to work on the command prompt by pressing SHIFT+ALT+`, but that didn’t work on e.g. Notepad++ and Visual Studio.

Solution:

I found out that you can fix that in the settings of the VM itself. You don’t need to shutdown you VM. Just do the following:

  • Open the Settings of you VM
  • Click on ‘Keyboard & Mouse’
  • Just under the list of Profiles, you will see a gear wheel button which you can expand.
  • Click in the gear wheel popup menu on the option ‘Edit profile’
  • In the popup window, click on the tab ‘Key Mapping’ and unselect the option ‘Enable Language Specific Key Mappings’. This will do the trick (a least for me).
  • Close all settings windows, return to your (running) VM and voila, the ‘~’ will work back again.

I assume that this will work on other Windows versions on VM's as well. Just give it a try.

Happy programming!

Monday, 9 May 2016

MS Access and LINQPad

Situation:

As most developers, using LINQ queries saves a lot of time and works absolutely great. For me one of the greatest tools for quick and easy querying data and testing code is LINQPad. However, sometimes you get a project where the (backend)database is MS Access (yes, it still happens, even in 2016 :) ).

Problem:

And there starts the problem. There is no MS Access driver for LINQPad, at least no free one.

Solution:

But we are lucky, LINQPad provides a way to create custom drivers. So one of my colleagues, Frank den Outer, made a driver for MS Access to enable you to connect to *.mdb and *.accdb and allows you to query on data from LINQPad on MS Access database (even with password protected ones). So the credits of this post goes to him!

See the screenshots below:






Our company, DNM, offers you this driver for free. You can download is here: MSAccessDataContextDriver.lpx. After the download, start LINQPad, and when creating a new connection, you can easily add the downloaded driver.

Happy programming!

Android Screen Recording on Mac

Scenario:

For one of the apps we are developing, I needed to make a screen cast of some strange behaviour inside the app on Android. But how can you record screen activity from a Android device on Mac OS X?

Solution:

After a little bit of searching, the solution was actually pretty simple. You need to do the following:

1. Install the Android Tool
Download the Android Tool from GitHub (please check out the GitHub project page to keep track of updates and news). The download gave you a zip file. Unzip the file and place the tool inside the application folder on your Mac.

2. Prepare your Android device
In order to be able to establish a successful communication between your Android device and the Mac, you have to enable the 'Developer Options'. Inside the Developer Options, you need to enable the 'USB Debugging' feature. If you like, you can also enable the feature that shows your touch actions on the screen.

3. Launch the Android Tool
Start the Android Tool (note: you may get the warning that the app is from an unidentified developer). Once the app is opened, simply plug in your Android device

4. Start Recording
The tool is as easy as it can be:
Click on the camera button to take a screenshot or click on the camcorder button for a screen recording. When done with screen recording, press the red square (stop) button which appeared on the camcorder button place. You can record as long as you wish :).
The files created will be stored in an 'AndroidTool' folder on your desktop.

Note: You won't be able to record audio with this tool and neither you can take screenshots of record videos of protected videos.

Last tip: once you have your screencast video file, put it through Handbrake. This will decreases you file size a lot (e.g. 8.3 MB to 2.4 MB)

Monday, 1 June 2015

Fix slow boot-up on Mac

Problem
Recently I ran into a frustrating issue on my new MacBook Pro Retina (with 512MB SSD). The time of (re)boot took a lot of time, holding the screen black for a long time.
I checked several tips, but it was not due to old hardware (...), also not that my disk was full (more than 50% free space).
I searched a lot and found a solution that works actually pretty well and seems really stupid to me (a kind of Microsoft-type-solution-when-something-unexpectedly-stop-working-well).

Solution
What you need to do is to go to System Preferences, and selecting Startup Disk. Then, select your primary disk, and hit ‘Restart’ from the same window.


That's all! It worked for me pretty well!
By the way, it seems that this happened after the update of OS X 10.10.3.

Wednesday, 26 March 2014

Format date on textbox in Lightswitch HTML client

The HTML client for Ligthswitch is nice, except that not everything is that easy to obtain as in the Silverlight version. So is formatting dates on 'view' screens. Despite setting it at the entity in the 'Server' part of the project, it doesn't show up on the HTML output.
Solution:
Add a 'postRender' script to the date field(s) you like to format.

  • Therefore, go to the (view)screen where you like to format the date.
  • Select the field which shows a date. Let say 'StartDate'.
  • Click on 'Write code' on top of the window and select 'StartDate_postRender'.
  • Add the following piece of code:

myapp.ViewProject.StartDate_postRender = function (element, contentItem) {
    // Write code here.
    contentItem.dataBind("value", function (value) {
        if (value) {
            $(element).text(value.format("dd-MM-yyyy"));
        }
    })
};


Done.

Tuesday, 11 June 2013

Free online 15GB+ storage alternative for Dropbox

Hi folks,

Dropbox is fine, but you can run out of space. There is a free alternative which give you even bigger storage, copy.com!
You start with 15GB and for every user who creates an account via yours, you both get 5 GB storage extra, for free.
So, start creating an account with this link: https://copy.com?r=2ClF1N and get the default 15GB + 5 GB extra, because of using this link (and I get 5 GB free as well :) ).

Copy.com supports both Microsoft and Mac OS X environment!

Thanks and have a nice day!

Wednesday, 1 May 2013

Time Machine - preparing to copy "forever"

Problem:
I just got a new HD in my iMac (HD replacement action of Apple). Got the latest MacOSX on it. So far so good, but placing back my data from my Time Machine backup disk, I ran into problems. I had first a message and sometimes errors, telling that my disk was not properly removed (however, that was done by the OS itself). I just restarted the computer and tried it again. I started with an action to place back some data (couple of MB's), just to try if everything was working well.
Well, it didn't. It was preparing to copy forever. And finder hang, couldn't shutdown the computer on the normal way. So, just hard reset...
Solution:
Due to the 'not properly removed' messages and errors, I decided to run the Disk Utility and from there I ran the 'Verify Disk' option on my Time Machine (TM) backup disk. This took about half an hour or so. The results it shown were all good (green messages).
But, guess what, after that, restoring data from my TM Backup worked fine. Depending on the amount of data I restored, it took just a little moment to 'prepare to copy' and then it started to place the data back on my computer just as aspected and with an appropriate speed!

Thursday, 11 April 2013

Visual Studio 2012 XML IntelliSense for URL Rewrite 2.0

Problem:
I am working on a web-project within VS2012. I was trying to implement url-rewriting as described at cache busting in ASP.NET by Mads Kristensen. I was running into the problem that VS2012 didn't recognize the tag inside the .
I got it to work/function (thanks to ScottGu's blogpost) after installing the URL Rewrite Extension on IIS7.x.
So far so good, but VS2012 intellisense still didn't recognize the tag.
Solution:
I searched around and found the post http://ruslany.net/2010/04/visual-studio-xml-intellisense-for-url-rewrite-2-0/ on RuslanY Blog. Unfortunately, the script didn't work on VS2012. Even changing a part of the code to var vs9CommonTools = shell.ExpandEnvironmentStrings( “%VS110COMNTOOLS%” );
However, a guy named Michal A. Valášek created an updated js script to get it to work on VS2012.
So I put the pieces together for your convenience, you can download it here (I called it rewrite2.1_vsintellisense). Note this script is just for VS2012! Just unpack the zip file, run the commandline window as administrator (elevated privileges), and execute the script file with cscript UpdateSchemaCache.js
Happy programming!

Wednesday, 3 April 2013

Visual Sourcesafe 2005 on Windows 8 64-bit

Problem:
I was running into problems when I tried to install Visual Sourcesafe 2005 (VS2005) on Windows 8 (64-bit) environment. And yes, I know, Sourcesafe is out-dated, but I still have to use it :(.
Anyway, I searched around but didn't find a solution. So I tried it myself to work something out, and with luck (and it is actually something stupid easy...)
Solution:
Just start the setup.exe of vs2005. You will run into the window 'Program Compatibility Assistant' (PCA), click on the option 'Run the program without getting help'.
You will get this PCA-window a couple of times, just continue clicking 'Run the program without getting help'. Finally you get in the ordinary installation procedure of VS2005 and you can install it as normal.
Once installed, it just works fine!

Edit: If it doesn't work, just verify if .NET framework 2.0 and 3.5 are installed (thanks Suren!)

Happy programming folks!

Friday, 7 December 2012

Error Value: 2147942523 on Scheduled Task for Powershell


Situation: 
One of our clients where struggling with SSRS2008 R2 in SharePoint 2010 integrated mode (two server farm, both 64-bit Windows 2008 R2).
It is well known that this version SSRS 2008 R2 (v10) delivers a really bad performing webpart on the first report that is requested at the beginning of the day. For your information: The older v9 version performs much better as well as the newer version (of SSRS 2012).
However, I tried several solutions, without any luck. I found a solution on Pavel Pawlowski's blog (http://www.pawlowski.cz/2011/07/solving-issue-long-starting-report-ssrs-2008), which suggest to run a powershell script to stop/start the SSRS service, and load a report in a webclient (read more details on his post).
Problem:
I tried to run the scheduled task with the following statement:
"powershell.exe -noprofile -executionpolicy RemoteSigned -file c:\dnm\RestartSSRS.ps1"
It didn't work, it shows the following errors:
Task category: Action failed to start
Description: Task Scheduler failed to launch action “powershell.exe -noprofile -executionpolicy RemoteSigned -file c:\dnm\RestartSSRS.ps1? in instance “{46caf0b2-50df-49ad-90d6-0f4f9fd203ae}” of task “\SSRS Recycle”. Additional Data: Error Value: 2147942523.
Then I get:
Task category: Action start failed
Description: Task Scheduler failed to start instance “{46caf0b2-50df-49ad-90d6-0f4f9fd203ae}” of “\SSRS Recycle” task for user “customerdomain\Administrator” . Additional Data: Error Value: 2147942523
Solution:
I turns out that in this situation the Task Scheduler cannot fire the 64-bit version of powershell (which powershell.exe will do). You need to explicit point to the 32-bit version.
What I did was, edit the scheduled task, go to the action-tab and open the edit action window of the action.
On 'Program/script', I entered: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
On 'Add arguments (optional), I entered: -noprofile -executionpolicy RemoteSigned -file c:\myScripts\RestartSSRS.ps1

Done, that solved the "Error Value: 2147942523" problem for me.
And the solution Pavel Pawlowski gave, works also! All credits to him!

Wednesday, 24 October 2012

Restore failed for Server '' (MS SQL Server 2008 R2)

Problem
Today, I tried to restore a MS SQL Server 2008 R2 backup file. From a production server, I made a backup file. I tried to restore that backup on a named instance of SQL Server on a test server (on a physical other machine), to do some tests on the data without disturbing the live environment. The database didn't exist on the restore location.
To get the picture correct: on the test server, I have a default MS SQL Server instance and an extra, named instance. The restore was performed on the named instance!
It failed...
I got the following error:
System.Data.SqlClient.SqlError: The operating system returned the error '5(Access is denied.)' while attempting 'RestoreContainer::ValidateTargetForCreation' on 'C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\pfwork.mdf'. (Microsoft.SqlServer.Smo)
Strange enough, I was logged in with full administrator privileges.
Solution
I found some possible reasons at http://stackoverflow.com/questions/7031792/sql-server-restore-error-access-is-denied, but that was not the case in my situation.
Having a closer look at the message above opened my eyes. It was trying to create the database file on the data folder of the default instance, instead of the data folder of the named instance. That location would be C:\Program Files\Microsoft SQL Server\MSSQL10_50.DEVSSRS\MSSQL\DATA\.
So, when you start a restore from a device file to a (not existing) database, verify the location in the 'Options' page of the 'Restore Database' window. In my case it was pointing to the default SQL Server instance, despite the default file location of the named instance where pointing to the correct place.

Tuesday, 16 October 2012

LINQ to SharePoint: linq query filter on multivalue lookup

Situation:
I have a SharePoint Foundation 2010 environment with a document library. One of the metadata on the documents is a multivalue lookup to a category list.
I used SPMetal to create entity classes for easy usage of linq to the different lists and libraries inside the SharePoint site.
Problem:
Inside a visual web part, I was trying to execute a linq query on the document library, filtering on a given category.
Example code:

QualityDataContext dc = new QualityDataContext(SPContext.Current.Web.Url);
// some other steps made
var mySelectedCat = dc.MyCategories.OrderBy(p => p.Title).Where(p => p.id == "CategoryOfInterestID")

var docs = dc.MyDocLib.OrderBy(p => p.Title).Where(p => p.Categories.Contains(mySelectedCat));

This goes wrong because in this situation linq is messing up with the "p.Categories" en the entity "mySelectedCat"

Solution:
I have searched a lot, without getting a right, easy solution. Some mentioned to use the 'old' "SPWeb, SPList, SPQuery and so on"-way. Others where trying to believe you that the sample above is working.
Sorry folks, it's not. The problem is that querying on the multivalue lookup just works after the data has been retrieved. So I uses the ToList() method to the 'docs' part, just before filtering. For performance reasons, I first get the whole list (I just needed the whole list) and then do the filtering on the moment I needed it.
So this results in the following piece of code that I am using to fill a tree view, grouped on main category and sub category with links to documents.
Note the 'ToList()' I am using, twice just straight in the beginning of the using section. This is doing the trick.

using (QualityDataContext dc = new QualityDataContext(SPContext.Current.Web.Url))
{
 var cats = dc.MyCategories.OrderBy(p => p.Title).ToList();
 var docs = dc.MyDocuments.OrderBy(p => p.Title).ToList();

 SPTreeView tv = new SPTreeView();

 var mainCat = cats.OrderBy(p => p.Category).GroupBy(p => p.Category);
 
 // Step through the main categories
 foreach (var item in mainCat)
 {
  TreeNode catNode = new TreeNode{ Text = item.Key, Value = item.Key };
  
  var subCats = cats.OrderBy(p => p.Title).Where(p => p.Category == item.Key);

  // Step through the sub categories
  foreach (var subCat in subCats)
  {
   TreeNode subCatnode = new TreeNode { Text = subCat.Title, Value = subCat.Id.ToString() };
   var subdocs = docs.Where(p => p.Categories.Contains(subCat));

   if (subdocs.Count() > 0)
   {
    foreach (var doc in subdocs)
    {
     string docUrl = doc.Path + "/" + doc.Naam;
     subCatnode.ChildNodes.Add(new TreeNode { Text = doc.Naam, ToolTip = doc.Title, NavigateUrl = docUrl, Target = "_blank" });
    }
    subCatnode.Collapse();
    catNode.ChildNodes.Add(subCatnode);
   }
  }
  tv.Nodes.Add(catNode);
 }
 this.Controls.Add(tv);

Tuesday, 25 September 2012

Report Server: Show/hide textbox by an expression

Today I was struggling with hiding a textbox on a report (in Report Builder) by using an expression. I tried to evaluate the number of subfunctions of a certain person. The evaluation worked, but the textbox didn't show up when 1 or more subfunctions were available.
The expression was:
=IIf((Count(Fields!Uid.Value, "dsSubFunctions")<1),False,True)
WRONG! The property you will set is named 'Hidden', so it's just the other way around:
=IIf((Count(Fields!Uid.Value, "dsSubFunctions")<1),True,False)
And stupid of me, it is just written right above the expression-textbox: 'Set the expression for: Hidden'

Anyway, just thought to share it, in case there are some more (lazy) programmers who don't read every single line of text Microsoft shows you :)

Wednesday, 19 September 2012

Cross-domain data with AJAX using JSON

I read some different blogs and sites about using JSON or JSONP in relation with AJAX requests in cross-domain environments.
I just want it to keep it as simple as possible.
Situation:
I have a local webservice, behind a firewall, which is only available from another website somewhere on the internet (ip-filtering). On that site I call the (local) webservice) using
$.ajax({
  type: "POST",
  url: 'http://<my url:portnumber>/myCustomService.asmx/SendMyRequest',
  data: "{name: '" + _name
  + "' , category: '" + _category
  + "' , address: '" + _address
  + "' , company: '" + _company + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
  // etc...

So, I figured out to use "access-control-allow-origin" with the value "*" as a custom header in IIS7.5
Problem:
However, adding the Acces-control-allow-origin=* doesn't work. After some struggling and some more research, in found the solution
Solution:
Besides this access-control-allow-origin, you need to add an extra entry, the "access-control-allow-headers" with value "content-type". So, just place inside your web.config the following data:

<configuration>
  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="access-control-allow-origin" value="*" />
        <add name="access-control-allow-headers" value="content-type" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>
</configuration>

Tuesday, 21 August 2012

Attachments in SharePoint List Item ARE searchable

Today I got a question by phone of one this blog-followers (hi Erwin!). His question was if attachments on SharePoint list items are searchable. I had to confess that I've never had this question before. A first quick search on the internet gave the answer: no!
But, that isn't the truth. I just search a bit around, because I was curious if that was really true. I found that list attachments are indexed in SharePoint search. And because of that, searchable!
The trick, or if you like the problem, is the presentation of the results by SharePoint. The results are not pointing to the attachment itself, but to the list item that contains that attachment. But in the description of the search result, you can see the words from the attachment that you searched for. This is a bit disappointing because the search result would be confusing and useless if the list item has multiple attachments. The user won’t know which attachment contains the words he searched for.
(thanks to Saji Viswambharan)

Tuesday, 7 August 2012

SharePoint designer workflow not updated

Today, I ran into another big SharePoint mystery (if you like mysteries, join the SharePoint world ;) ). A couple of weeks ago, I wrote a workflow in SharePoint designer (SPD) on a SharePoint Foundation environment. So far, so good.
Problem:
Today, I had to update/fix the workflow because I forgot a little step. And guess what, it didn't work. The updates on the workflow were not applied. Although a new version of the workflow was present on the site, the changed were not. Rebooting the entire SharePoint machine didn't solve this. Arghhhhhh..... But lucky me, after some search, I noticed that I was not the only one...
Solution:
It seems that SPD (sometimes = randomly I guess) forgot to empty his own application cache. A republish of a workflow is then done with the cached (=old) info. This is due to a mismatch between the server's activity and the SPD client's cached activity. So:
  1. Close SPD.
  2. Open “My Computer”.
  3. Go to %System Drive%\Documents and Settings\%user%\Local Settings\Application Data\Microsoft\WebSiteCache (If you are running Vista, that path is different - look for %System Drive%\Users\%user%\AppData\Local\Microsoft\WebSiteCache).
  4. Go to a directory that looks similar to the name of the website you were connecting to. (Alternatively, you can just delete all these directories and everything should work when you boot SPD).
  5. Delete the assembly with the name similar to the one you are changing.
  6. Boot SPD.
  7. You can now work with your updated activity.
Good luck and have fun!

Tuesday, 10 July 2012

Problems with SPUtility.SendEmail in custom timer job

Last week I ran into a strange problem. I wrote a custom timer job which will send reminder emails to employees who haven't finished their task after a certain time.
Problem(s):
Sending emails is easy, by using the SPUtility.SendEmail function. Well, at least it should be easy. There are a lot of code samples, so search around for some if you need it. However, again I ran into a SharePoint problem. This function returns a boolean value and gave me 'false' all the time. I tried to use the ordinary mail method of System.Net.Mail. There I got an error about "Message rejected as spam by Content Filtering". Some research of the IT department on Exchange did not solve this problem.
Well, I went back to the SPUtility.SendEmail function. I turned out that using the StringDictionary gave some problems as well as using HTML tags. Using plane text and one of the other overloads that doesn't use the StringDictionary results in a successful send action. But I needed a formatted message (sending some links).
The LOG files gave some extra information on the 'false' action. And yes, it shows why it didn't send the messages: 550 5.7.1 Message rejected as spam by Content Filtering.
Solution:
The solution I found (here) was relatively easy. Bypassing the content filter for a specific email address (or even sender domain). To do this, you need to resort to the Exchange shell (EMS) to manage it.

  1. Click on Start > All Programs > Microsoft Exchange 20xx > Exchange Management Shell. Note, this works for at least Exchange 2007 and 2010 versions.
  2. Create the bypass for the 'from' email address you use when sending the email from a timer job:
    Set-ContentFilterConfig -BypassedSenders somebody1@mycompany.com, somebody2@mycompany.com
Note: You need to realize that spammers can spoof the 'from' address and this would allow spam to get thru.
So, after all, it was not really a SharePoint problem, but an Exchange 'problem'.