DEV Community

Jorge
Jorge

Posted on • Originally published at jorge.aguilera.soy on

Publicar en Linkedin desde Gmail

WARNING

Para poder publicar en Linkedin necesitarás autentificar tu usuario y obtener un acccess token, una cadena de caracteres que te identifica y que NO debes compartir. NO es tu usuario y passsword (pero casi) y se necesita realizar un flujo "OAuth" para obtenerlo. En este post comparto tanto el código como una aplicación ya desplegada que podrás usar para ello.

Linkedin, la plataforma del postureo, tiene un API que puedes usar, entre otras cosas, para publicar textos, artículos, imágenes, etc de tal forma que puedes usar herramientas externas o incluso hacerte tu propia integración. En este post vamos a investigar cómo podemos publicar en esta red desde nuestra cuenta de Google de tal forma que al enviarnos un correo con un subject determinado, Google lo detecte y ejecute un script que publique el cuerpo del correo automáticamente

De esta forma un usuario no necesita entrar en la página de Linkedin y usar el interface que ofrece, sino que puede usar el editor del correo, programarlos, etc y de esta forma no perder el foco en lo que está realizando en ese momento.

Requisitos

  • Cuenta en Linkedin

  • Cuenta Gmail

Linkedin

Como ya se ha comentado, Linkedin implementa una flujo OAuth para la autentificación del usuario. Esto quiere decir, por una parte, que se requiere de su intervención para generar un token que lo identifique y por otra parte, una aplicación que realize el flujo.

Crear la aplicación

En primer lugar crearemos una aplicación en https://developer.linkedin.com/

En este enlace puedes encontrar los pasos a realizar de forma detallada

https://guides.micronaut.io/latest/micronaut-oauth2-linkedin-maven-java.html#create-a-linkedin-app

Identificarse y obtener el Token

Una vez realizados los pasos indicados obtendremos un par de claves (ClientId y ClientSecret) que servirán para identificar a nuestra aplicación. Esta pareja de claves hay que mantenerlas guardadas y no compartirlas

Si sigues la guía al completo (no es necesario) al final tendrías una aplicación que te permitiría hacer login en la misma con tu cuenta de Linkedin …​ y nada más. Así que he preparado esta aplicación , basada en este tutorial, que una vez te identificas en ella obtienes tu userId y un accessToken

https://gitlab.com/puravida-software/linkedin-accesstoken

Básicamente esta aplicación permite al usuario autentificarse en Linkedin y obtener los datos necesarios para publicar un post en la red. Esta aplicación se ejecutaría en tu local por lo que si has seguido los pasos de la guia anterior y ejecutado esta aplicación, obtendrás estos datos de forma segura (el código de la aplicación es abierto así que puedes revisarlo para comprobarlo)

Si todo esto te resulta complicado (no es fácil pero es lo que hay) y confías en mí, he desplegado esta misma aplicación en

https://linkedin-pvidasoftware.cloud.okteto.net/

la cual te solicitará acceso a tu cuenta y que le des permisos para publicar en tu nombre. Obviamente aquí podría usar tus datos para liartela así que te corresponde a tí decidir qué hacer (La otra opción es que te pongas en contacto conmigo y hablemos 😉 )

Gmail

La parte "fácil" es crear el script de Google. Para ello iremos a

https://script.google.com/home

y crearemos un nuevo proyecto (yo lo he llamado "Publicar en Linkedin")

Nos aparecerá un pequeño código que reemplazaremos por este:

const author='NQxxxxxxx'; // Tu userId
const accessToken='AQUg-xxxxxxx'; // El accessToken, una cadena superlarga

const url = 'https://api.linkedin.com'
const label = 'Publicar en Linkedin';
const lifecycleState='PUBLISHED';
const visibility = 'PUBLIC';

function checkEmail() {
    try{
        unreadEmail()
    }catch(error){
      Logger.log(error)
    }
}

function unreadEmail() {
  const ts = GmailApp.search(`subject:${label} is:unread to:me from:me`);
  ts.forEach(t => {
    t.getMessages().forEach(m => {
      processEmail(m);
      m.markRead();
    });
  });
}

function processEmail(m) {

  const images = m.getAttachments();
  let medias = [];
  if( images ){
    images.forEach( (a)=>{ medias.push(uploadImage(a))} )
  }

  const body=html2text(m.getBody())

  var payload = {
    "author": "urn:li:person:"+author,
    "lifecycleState":lifecycleState,
    "visibility": {
      "com.linkedin.ugc.MemberNetworkVisibility":visibility
    },
    "specificContent":{
      "com.linkedin.ugc.ShareContent":{
        "shareCommentary":{
          "text": body
        },
        "shareMediaCategory" : medias.length ? "IMAGE" : "NONE",
        "media":medias
      }
    }
  };

  var options = {
    'method' : 'post',
    'contentType': 'application/json',
    'payload': JSON.stringify(payload),
    'headers': {
      'Authorization': `Bearer ${accessToken}`,
      'X-Restli-Protocol-Version': '2.0.0'
    }
  };
  Logger.log(options)
  const resp = UrlFetchApp.fetch(`${url}/v2/ugcPosts`, options);
  Logger.log(resp)
}

function html2text(body){
  return `${body}`.replace('<br>','\n').replace('</div>','\n\n').replace(/<[^>]+>/g, '').replace("&quot;",'"')
}

function uploadImage(attachment) {

  var imgPayload = {
    "registerUploadRequest": {
        "recipes": [
            "urn:li:digitalmediaRecipe:feedshare-image"
        ],
        "owner": "urn:li:person:"+author,
        "serviceRelationships": [
            {
                "relationshipType": "OWNER",
                "identifier": "urn:li:userGeneratedContent"
            }
        ],
        "supportedUploadMechanism":[
          "SYNCHRONOUS_UPLOAD"
        ]
    }
  }
  var imgOptions = {
    'method' : 'post',
    'contentType': 'application/json',
    'payload': JSON.stringify(imgPayload),
    'headers': {
      'Authorization': `Bearer ${accessToken}`,
      'X-Restli-Protocol-Version': '2.0.0'
    }
  };
  const resp = UrlFetchApp.fetch(`${url}/v2/assets?action=registerUpload`, imgOptions);
  Logger.log(resp);

  const json = JSON.parse(resp)
  const uploadUrl = json.value.uploadMechanism["com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest"].uploadUrl;
  const mediaId = json.value.asset;

  var optionsImage = {
    method : "put",
    payload : attachment.copyBlob(),
    headers:{
      'Authorization': `Bearer ${accessToken}`,
      'Accept':'*/*'
    }
  };
  Logger.log(uploadUrl)
  var respImage = UrlFetchApp.fetch(uploadUrl, optionsImage).getContentText();
  Logger.log(respImage)

  return {
    status:'READY',
    media: mediaId
  }

}
Enter fullscreen mode Exit fullscreen mode

Una vez salvado el código vamos a probar que funciona correctamente:

  • Envíate un correo a tí mismo con el subject "Publicar en Linkedin" (las mayusculas da igual) en formato texto plano

  • NO lo abras

  • En la parte superior del editor del script verás un listbox donde puedes seleccionar qué método ejecutar. Asegurate que se encuentra seleccionado checkEmail

  • Al lado de este listbox tienes el botón Ejecutar. Al pulsarlo aparecerán logs en la parte inferior de la pantalla y si no aparece ninguno de error tu correo habrá sido publicado en Linkedin. Puedes ir a tu cuenta y comprobarlo

  • Comprueba que el email se ha marcado como leído

Automatización

Una vez comprobado que el proceso funciona podemos decirle a Google que cada cierto ejecute este proceso:

  • En el menú de la izquierda pulsa en el reloj y seleciona "Activadores"

  • Añadir un Activador (botón abajo a la derecha)

  • Seleccionamos checkEmail como método a ejecutar y configuramos el temporizador a usar. Yo por ejemplo estoy usando cada hora

  • Guardamos el activador

Básicamente, cada hora Google ejecuta mi script en mi cuenta de gmail y comprueba si hay correos sin enviar con el subject "Publicar en Linkedin" y lo publica.

Tips

Este API permite publicar texto acompañado de fotos.

El problema es que si te envías el email en formato enriquecido hay que transformarlo (quitar los divs, span, …​.) por lo que lo más sencillo es mandarlo como texto plano.

Puedes adjuntar imágenes al email y el script lo detecta y las sube a Linkedin junto al texto. NO he probado el máximo que puedes adjuntar, sólo 3 ó 4. Todo es probar

Top comments (0)