Migrating Inline Images and Attachments to Freshdesk

Hi All -

We are manually migrating about 900k tickets from Help Scout to Freshdesk and we’re running into a bit of an issue with inline images and attachments (specifically, the best way to get them off of Help Scout’s cloud and onto ours or Freshdesk’s).

Inline images in particular are embedded in the body tag via Cloudfront URLs, like this:

"body": "Some message text.<br><br><img width=\"1200\" height=\"839\" style=\"height:8.7395in;\" src=\"https://server.cloudfront.net/inline/number/longimagepath.png\" alt=\"\"/>",

And attachments are in a separate field and hosted on https://secure.helpscout.net

Curious if anyone else has run into this issue and what your solution was. We were told by FD that they couldn’t import inline images if they were going to help us with the migration so I’m guessing they don’t have a way to automatically replace these URLs with their own.

Hey Jared,

I figured out a solution to get inline images and pass them through to a third party api. This will need to be tweaked to your specific use case but this is how I converted FreshService inline attachments to base64 and got the content type:

Code to process/ identify inline attachments:

var btoa = require('btoa');
const { JSDOM } = require('jsdom');

const dom = new JSDOM(imgbody);
    var urls = [];

    const imgElements = dom.window.document.querySelectorAll('img');
    urls = Array.from(imgElements).map(imgElement => imgElement.getAttribute('src'));

if(urls){
var converturl = await convertAttachment(urls[url]);
        var type = converturl[1].get("Content-Type");
        var filetype;
        if(type.includes('png')){
          filetype = "png"
        } else if(type.includes('jpeg')){
          filetype = "jpeg"
        } else {
          filetype = 'png'
        }

        var attachbody ={
          "number": dmiticnum,
          "u_attachment1_name": `Inline Attachment${url}.${filetype}`,
          "u_attachment1": converturl[0]
        }
}

Convert Attachment looks like this:

async function convertAttachment(url){
  var base64String;
  var headers;
  await fetch(`${url}`)
          .then(res => res.arrayBuffer())
            .then(arrayBuffer => {
            const octetStream = new Uint8Array(arrayBuffer);
            base64String = btoa(octetStream.reduce(function (data, byte) {
            return data + String.fromCharCode(byte);
              }, ''))
        }).catch(err=>{
        console.log(`There was an error see the next line for the returned error.`); 
        console.log(err)
        });
        await fetch(`${url}`)
          .then(res => {
            headers = res.headers
          })
          .catch(err=>{
        console.log(`There was an error see the next line for the returned error.`); 
        console.log(err)
        });

        return [base64String, headers];
}

I also have devised a util function using the unirest library to upload attachments:

var unirest  =  require('unirest');
function createAttachment(args){

	var endpoint= args.endpoint	

	unirest.put(endpoint)
		.headers({  
            Authorization : "Basic " + fsapiencode,
            "Content-Type" : "multipart/form-data"
        })
		.attach('attachments[]', args.url,
        {
            filename: args.name,
            contentType: args.type
        })
		.end(function (response) {
			if (response.status < 400) {	
				console.log(`Attachment upload successful on ticket ${args.endpoint}.`);
			}else{
				console.log({"attachment body": response.body, "attachment status": response.status});
			}
		});
}

var args = {
                            id: newid,
                            name: attach.name,
                            url: attach.attachment_url,
                            type: attach.content_type,
                            endpoint: `https://${domain}.freshservice.com/api/v2/tickets/${newid}`
                        }

Hope this helped even if it is a late response!