Search code examples
c#asp.net-mvcapiabcpdfmailmessage

Generating a pdf from html and attaching it to an email


I'm having an issue with some code that can be split into two issues, I seem to be capable of having either of the two workings, just not at the same time. The two issues are generating a pdf from a webpage which I am using the third party Nuget package ABCpdf for and the second part of the issue is then attaching that email to an email to send to clients.

Generating a pdf from a html source using ABCpdf

The pdf is generated using a webpage which acts like a normal view. The pdf generator is hosted in an azure cloudservice webrole and uses the following code:

byte[] pdfBytes;
try
{
    // set Liscence key for ABCpdf
    XSettings.InstallLicense("[ABCpdf_LISCENCE_KEY]");

    using (Doc theDoc = new Doc())
    {
        // generate the pdf, I have attempted generating and transfering as stream, string, and byte[]
        MemoryStream ms = new MemoryStream();
        theDoc.HtmlOptions.Engine = EngineType.Gecko; // this allows use of most recent HTML
        theDoc.AddImageUrl(url); // this adds the page at the provided url to the document
        theDoc.Save(ms); // this creates the document itself
        pdfBytes = ms.ToArray(); // this converts it to a byte array for transport to the main application
    }
}
return Ok(pdfBytes); // return the data to the main application

Performing the ABCpdf code within a separately hosted cloud service is the method recommended by ABCpdf so I'm fairly certain I am doing this correctly. At the very least when I ran the output which the main application received back something that looked fairly pdf like:

Attaching the generated pdf to an email

The following code is taken from the main application and is used to both call the cloud service to get the pdf before attaching the output to an email and sending it:

public async void SendQuotePDF(Quote quote, string fileName, string subject, string body)
{
    try
    {
        //Get pdf from cloud service hosted ABCpdf
        string requestURL = @"http://[CloudServiceURL]/api/PdfGenerator/GetWebPageInfo/?url=http://google.com"; // I'm currently just using google as a testsite to generate the pdf of
        byte[] pdfBytes = await GetPdfBytesFromUrlAsync(requestURL);

        if (pdfBytes != null)
        {
            // For each client attached to the quote
            foreach (QILT.Models.DBModels.Client c in quote.Clients)
            {
                //Get SenderEmail address and Password from settings
                string senderEmailAddress = ConfigurationManager.AppSettings.Get("SenderEmail");
                string senderPassword = ConfigurationManager.AppSettings.Get("SenderEmailPassword");

                //Create email message
                MailMessage mailMessage = new MailMessage(senderEmailAddress, c.Email);

                // Attach the generated pdf
                mailMessage.Attachments.Add(new Attachment(new MemoryStream(pdfBytes), fileName, System.Net.Mime.MediaTypeNames.Application.Pdf));
                mailMessage.IsBodyHtml = true;

                // send the email
                SmtpClient smtp = new SmtpClient();
                smtp.Host = "smtp.office365.com";
                smtp.EnableSsl = true;
                NetworkCredential NetworkCred = new NetworkCredential();
                NetworkCred.UserName = senderEmailAddress;
                NetworkCred.Password = senderPassword;
                smtp.UseDefaultCredentials = true;
                smtp.Credentials = NetworkCred;
                smtp.Port = 587;

                //Send email
                smtp.Send(mailMessage);
            }
        }
    }
}

public async System.Threading.Tasks.Task<byte[]> 
GetPdfBytesFromUrlAsync(string uri)
{
    pdfBytes = null;
    try
    {
        HttpClient httpClient = new HttpClient())
        {
            try
            {
                pdfBytes = await httpClient.GetByteArrayAsync(uri);
            }
            catch (Exception e) { e = null; }
        }
        //Return pdf as byte array
        return pdfBytes;
    }
    return null;
}

The Result

Running this code from a published site the following occurs: - An email is sent to each client - The email has a file attached which, on opening, simply says "something stopped this from opening". - The API (as the main application is functioning as an API) returns a 500 internal server error. This is strange as while debugging it reaches it's final return statement with normal output data and appears to finish successfully. With the pdf not generated/attached it outputs 200 ok along with it's data model.

I'm not sure where to take this at this point. I can't see anything obviously wrong with the code from trying solutions from other questions, both parts of the problem appear to work in debugger and no errors are thrown during the running of the code. I have tried passing the data back from the cloud service as byte[], Stream, and string and I have tried just about every conversion method I can find for moving between the types but no matter what I do the output and problem appear to be the same.

Nota Bene

I have had to compact my code slightly to fit into this question, things such as setting the email body etc have been done but I have only left the code relating to the pdf. If there are any sections of code which you feel I have missed and you need to see please let me know.


Solution

  • I have had an issue like this and it was because I was attempting to run it from a non-controller class.

    Try moving it to a controller class.