weeraa
weeraa

Reputation: 1195

Html table convert as excel and send via email

I'm developing an app which can generate a excel file using html table. Up to now I developed html table download as excel file part. (This happens in client side with javascript). Now I need to send email with that attachment (The excel file) to particular person's email address. So I'm confuse how to do this, because up to now I generate excel in client side and need to send that file via email. In this case is it needed to copy client side excel to the server? If so how to do this? Please give me a direction.

Update 1 (Adding codes)

This is the javascript, that I used to download html table as excel to client side.

    var tablesToExcel = (function () {
        var uri = 'data:application/vnd.ms-excel;base64,'
        , tmplWorkbookXML = '<?xml version="1.0"?><?mso-application progid="Excel.Sheet"?><Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">'
          + '<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office"><Author>Axel Richter</Author><Created>{created}</Created></DocumentProperties>'
          + '<Styles>'
          + '<Style ss:ID="Currency"><NumberFormat ss:Format="Currency"></NumberFormat></Style>'
          + '<Style ss:ID="Date"><NumberFormat ss:Format="Medium Date"></NumberFormat></Style>'
          + '</Styles>'
          + '{worksheets}</Workbook>'
        , tmplWorksheetXML = '<Worksheet ss:Name="{nameWS}"><Table>{rows}</Table></Worksheet>'
        , tmplCellXML = '<Cell{attributeStyleID}{attributeFormula}><Data ss:Type="{nameType}">{data}</Data></Cell>'
        , base64 = function (s) { return window.btoa(unescape(encodeURIComponent(s))) }
        , format = function (s, c) { return s.replace(/{(\w+)}/g, function (m, p) { return c[p]; }) }
        return function (tables, wsnames, wbname, appname) {
            var ctx = "";
            var workbookXML = "";
            var worksheetsXML = "";
            var rowsXML = "";

            for (var i = 0; i < tables.length; i++) {
                if (!tables[i].nodeType) tables[i] = document.getElementById(tables[i]);
                for (var j = 0; j < tables[i].rows.length; j++) {
                    rowsXML += '<Row>'
                    for (var k = 0; k < tables[i].rows[j].cells.length; k++) {
                        var dataType = tables[i].rows[j].cells[k].getAttribute("data-type");
                        var dataStyle = tables[i].rows[j].cells[k].getAttribute("data-style");
                        var dataValue = tables[i].rows[j].cells[k].getAttribute("data-value");
                        dataValue = (dataValue) ? dataValue : tables[i].rows[j].cells[k].innerHTML;
                        var dataFormula = tables[i].rows[j].cells[k].getAttribute("data-formula");
                        dataFormula = (dataFormula) ? dataFormula : (appname == 'Calc' && dataType == 'DateTime') ? dataValue : null;
                        ctx = {
                            attributeStyleID: (dataStyle == 'Currency' || dataStyle == 'Date') ? ' ss:StyleID="' + dataStyle + '"' : ''
                               , nameType: (dataType == 'Number' || dataType == 'DateTime' || dataType == 'Boolean' || dataType == 'Error') ? dataType : 'String'
                               , data: (dataFormula) ? '' : dataValue
                               , attributeFormula: (dataFormula) ? ' ss:Formula="' + dataFormula + '"' : ''
                        };
                        rowsXML += format(tmplCellXML, ctx);
                    }
                    rowsXML += '</Row>'
                }
                ctx = { rows: rowsXML, nameWS: wsnames[i] || 'Sheet' + i };
                worksheetsXML += format(tmplWorksheetXML, ctx);
                rowsXML = "";
            }

            ctx = { created: (new Date()).getTime(), worksheets: worksheetsXML };
            workbookXML = format(tmplWorkbookXML, ctx);

            var link = document.createElement("A");
            link.href = uri + base64(workbookXML);
            link.download = wbname || 'Workbook.xls';
            link.target = '_blank';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        }
    })();

Still I do not have idea to save generated excel to server and send it as email.

Upvotes: 1

Views: 3675

Answers (2)

MustafaMahmoud
MustafaMahmoud

Reputation: 11

AS per our discussion: 1. you need to send data from client to server you can use this code to do this sending headers and values to server using ajax and you can also filter columns as you want

function SaveToServer() {
        var gov = GetHeaders('tbl');

        $.ajax({
            url: '@Url.Content("~/Home/ReciveData")',
            data: { headers: JSON.stringify(gov.heasers), data: JSON.stringify(gov.data) },
            success: function (data) {
         // Success
            },
            error: function (xhr) {
            }
        });

    }

    function GetHeaders(tableName) {

        table = document.getElementById(tableName);
        var tbl_Hdata = [];
        var tbl_Data = [];
        for (var i = 0, row; row = table.rows[i]; i++) {
            var rowData = [];
            for (var j = 0, col; col = row.cells[j]; j++) {
                // add column filter
                if (i == 0) {
                    tbl_Hdata.push(col.innerHTML);
                }
                else {
                    rowData.push(col.innerHTML);
                }
            }
            if (i > 0) {
                tbl_Data.push(rowData);
            }
        }

        return { heasers: tbl_Hdata, data: tbl_Data };
    }
  1. now we want to recive this data and convert it to datatable to save it to excel in server side using NPOI

    public void ReciveData(string headers, string data)
    {
        #region Read Data
        List<string> tbl_Headers = new List<string>();
        List<List<string>> tbl_Data = new List<List<string>>();
        tbl_Headers = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(headers);
        tbl_Data = Newtonsoft.Json.JsonConvert.DeserializeObject<List<List<string>>>(data);
        #endregion
    
        #region Create Data Table
        DataTable dataTable = new DataTable("Data");
        foreach (var prop in tbl_Headers)
        {
            dataTable.Columns.Add(prop);
        }
        DataRow row;
        foreach (var rw in tbl_Data)
        {
            row = dataTable.NewRow();
    
            for (int i = 0; i < rw.Count; i++)
            {
                row[tbl_Headers[i]] = rw[i];
            }
            dataTable.Rows.Add(row);
        }
        #endregion
    
        #region Save To excel
        string path = @"D:\";
        string fileName = "";
        GenerateExcelSheetWithoutDownload(dataTable, path, out fileName); 
        #endregion
    
    }
    
    public bool GenerateExcelSheetWithoutDownload(DataTable dataTable, string exportingSheetPath, out string exportingFileName)
    {
        #region Validate the parameters and Generate the excel sheet
        bool returnValue = false;
        exportingFileName = Guid.NewGuid().ToString() + ".xls";
    
        if (dataTable != null && dataTable.Rows.Count > new int())
        {
            string excelSheetPath = string.Empty;
            #region Check If The directory is exist
            if (!Directory.Exists(exportingSheetPath))
            {
                Directory.CreateDirectory(exportingSheetPath);
            }
    
            excelSheetPath = exportingSheetPath + exportingFileName;
            FileInfo fileInfo = new FileInfo(excelSheetPath);
            #endregion
    
            #region Write stream to the file
            MemoryStream ms = DataToExcel(dataTable);
            byte[] blob = ms.ToArray();
            if (blob != null)
            {
                using (MemoryStream inStream = new MemoryStream(blob))
                {
                    FileStream fs = new FileStream(excelSheetPath, FileMode.Create);
                    inStream.WriteTo(fs);
                    fs.Close();
                }
            }
            ms.Close();
            returnValue = true;
            #endregion
        }
    
        return returnValue;
        #endregion
    }
    
    private static MemoryStream DataToExcel(DataTable dt)
    {
        MemoryStream ms = new MemoryStream();
        using (dt)
        {
    
            #region Create File
            HSSFWorkbook workbook = new HSSFWorkbook();//Create an excel Workbook
            ISheet sheet = workbook.CreateSheet("data");//Create a work table in the table
    
            int RowHeaderIndex = new int();
            #endregion
    
            #region Table Headers
            IRow headerTableRow = sheet.CreateRow(RowHeaderIndex);
            if (dt != null)
            {
                foreach (DataColumn column in dt.Columns)
                {
                    headerTableRow.CreateCell(column.Ordinal).SetCellValue(column.Caption);
                }
                RowHeaderIndex++;
            }
            #endregion
    
            #region Data
    
            foreach (DataRow row in dt.Rows)
            {
                IRow dataRow = sheet.CreateRow(RowHeaderIndex);
                foreach (DataColumn column in dt.Columns)
                {
                    dataRow.CreateCell(column.Ordinal).SetCellValue(row[column].ToString());
                }
                RowHeaderIndex++;
            }
            #endregion
    
            workbook.Write(ms);
            ms.Flush();
            //ms.Position = 0;
        }
        return ms;
    }
    
  2. Now you can send this file as attachment in mail

Upvotes: 1

Panagiotis Kanavos
Panagiotis Kanavos

Reputation: 131483

You can't create Excel files with HTML tables. This is a hack that's used to fake actual Excel files. Excel isn't fooled, it recognizes the HTML file and tries to import the data using defaults. This will easily break for any number of reasons, eg different locale settings for decimals and dates.

Excel files are just zipped XML files. You can create them using XML manipulation, the Open XML SDK or a library like EPPlus.

Creating an Excel file with EPPlus is as easy as calling the LoadFromCollection or LoadFromDatatable method. The sheet can be saved to any stream, including FileStream or MemoryStream. A MemoryStream can be used to send the data to a web browser as shown in this answer:

public ActionResult ExportData()
{

    //Somehow, load data to a DataTable

    using (ExcelPackage package = new ExcelPackage())
    {
        var ws = package.Workbook.Worksheets.Add("My Sheet");
        //true generates headers
        ws.Cells["A1"].LoadFromDataTable(dataTable, true);

        var stream = new MemoryStream();
        package.SaveAs(stream);

        string fileName = "myfilename.xlsx";
        string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

        stream.Position = 0;
        return File(stream, contentType, fileName);
    }
}

Mail attachments can also be created from a MemoryStream. The Attachment(Stream, string,string) constructor accepts any stream as input. The example above could be modified to create an attachment instead of sending the data to the browser:

public void SendData(string server, string recipientList)
{

    //Same as before
    using (ExcelPackage package = new ExcelPackage())
    {
        var ws = package.Workbook.Worksheets.Add("My Sheet");
        ws.Cells["A1"].LoadFromDataTable(dataTable, true);
        var stream = new MemoryStream();
        package.SaveAs(stream);

        string fileName = "myfilename.xlsx";
        string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

        stream.Position = 0;
        SendExcel(server,recipientList);
    }
}

void SendExcel(string server, string recipientList)
{
        //Send the file
        var message = new MailMessage("[email protected]", recipientList);
        message.Subject = "Some Data";
        Attachment data = new Attachment(stream, name, contentType);
        // Add the attachment to the message.
        message.Attachments.Add(data);
        // Send the message.
        // Include credentials if the server requires them.
        var client = new SmtpClient(server);
        client.Credentials = CredentialCache.DefaultNetworkCredentials;
        client.Send(message);
    }
}

UPDATE

Generating an XSLX table on the client side becomes a lot easier if you use a library like js-xlsx. There's even a sample that generates an XLSX file from an HTML table

Upvotes: 0

Related Questions