I first wrote about this here, but I've since received several requests for more prescriptive advice on the subject. Again you can never be sure without understanding the exact usage pattern because the results really do vary widely but here's some general guidelines that may be useful.
The choice (String vs. StringBuilder) usually turns not on whether the strings are known at compile time or not, but rather on whether the number of appends is known. This is especially true if you can't really be sure of the sizes in advance either (i.e. they might vary).
x = f1(...) + f2(...) + f3(...) + f4(...)
if (...) x += f1(...) if (...) x += f2(...) if (...) x += f3(...) if (...) x += f4(...)
StringBuilder sb;
if (...) AppendF1(sb,...) if (...) AppendF2(sb,...) if (...) AppendF3(sb,...) if (...) AppendF4(sb,...)
if (...) sb.Append(f1(...)) if (...) sb.Append(f2(...)) if (...) sb.Append(f3(...)) if (...) sb.Append(f4(...))