In your
SendTestEmail
code you have built up a list of people which you step through to generate the personalised message.
On your first pass through this you are going to set up that message as "Dear Joe" and call the
SendEmail
method.
But you are passing the list of people into that method as well, and within that method (SendEmail) you explicitly say
foreach (Person person in people)
mailing.Bcc.Add(person.EmailAddress);
In other words, send a copy of the "current" text (Dear Joe) to everyone in the list!
If you remove those two lines then you should resolve the issue but you never really set up who the email is to be sent to anyway
mailing.To.Add(fromAddress);
is sending it to the hard-code from address.
You would be better off doing some rethinking of your design - stick to certain principles, for example a method should really do one thing and one thing only.
A hint to make the personalisation a little tidier ... set up the text once but with a placeholder for the name e.g.
string emailText = ("Dear {0} \n\nThis is an email to inform you that your training course on the 1st of January has been cancelled");
Then to personalise the text you can do something like
emailText = String.Format(emailText, p.FirstName);