linkedin-api
linkedin-api copied to clipboard
Send In Mail message using Sales Navigator
Hello, I would like to send a message by using the premium tool Sales Navigator to non-connected people. Any idea how can I do this?
@manuelrech were you able to accomplish this?
Nope I decided to use Selenium to achieve that
All requests should ofc contain standard headers.
One way is to check for credits first here using GET:
https://www.linkedin.com/sales-api/salesApiCredits?q=findCreditGrant&creditGrantType=LSS_INMAIL
In response, you get something like this where value property (of first child of elements) is number of remaining credits
{ "elements": [ { "type": "LSS_INMAIL", "value": 150, "id": 76486807 } ], "paging": { "count": 10, "start": 0, "links": [] } }
Then actual send message request is here using POST:
https://www.linkedin.com/sales-api/salesApiMessageActions?action=createMessage
All standard headers should be included.
Request body/payload:
{ "createMessageRequest": { "subject": "Hi", "body": "How are you?\n\n\nYOUR NAME", "trackingId": GENERATED, "copyToCrm": false, "recipients": [ "urn:li:fs_salesProfile:(ACwAADoB8t8Bn44ehqxo-qK8ZEWvGy6rQ3PhBC0,NAME_SEARCH,Kdir)" ] } }
hi @M1z23R ! I'm trying what you suggested, but I'm getting the following error:
{'code': 'SALES_SEAT_REQUIRED', 'serviceErrorCode': 784523211, 'status': 403}
Any idea about what is going wrong based on that error? Here's my code:
from linkedin_api import Linkedin
api = Linkedin(email, password)
params = {
'q': 'findCreditGrant',
'creditGrantType': 'LSS_INMAIL',
}
r = api.client.session.get(url='https://www.linkedin.com/sales-api/salesApiCredits', params=params)
print(r.json())
Thanks!
It's maybe a stupid question from me but, do you have Sales Navigator account or are you using free account? I can't remember - I think there are like 1,2,5 free InMails with free account so that's why I am asking
Hi @M1z23R! I'm using a paid account, but maybe I should be authenticating directly to linkedin sales. If you have any code that you used at that time, I'd appreciate.
I am not sure how familiar you are with JS, but I am writing a chrome extension, and I am looking up this repo for references, endpoints, payload structures, etc. Here is a code you can enter in console in dev tools in Chrome (while on linkedin):
const getCSRF = () => {
for (const cookie of document.cookie.split("; ")) {
const key = cookie.split("=")[0];
const value = cookie.split("=")[1];
if (key == "JSESSIONID") {
return value.substring(1, value.length - 1);
}
}
return "";
};
const req = await fetch(
`https://www.linkedin.com/sales-api/salesApiCredits?q=findCreditGrant&creditGrantType=LSS_INMAIL`, {
method: "GET",
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: [
["csrf-token", getCSRF()],
["x-li-deco-include-micro-schema", "true"],
["x-restli-protocol-version", "2.0.0"],
],
redirect: "follow",
}
);
const data = await req.json();
console.log(data);
})();
@WittmannF Try to adjust it to your needs and try to make it work with this python tool, it should work the same way.
Thanks @M1z23R ! I was able to convert your code to python using GPT:
import requests
def getCSRF(cookies):
for cookie in cookies.split("; "):
key = cookie.split("=")[0]
value = cookie.split("=")[1]
if key == "JSESSIONID":
return value[1:-1]
return ""
# Assuming you have cookies as a string (like in JS's document.cookie)
cookies_str = "YOUR_COOKIES_STRING_HERE"
csrf_token = getCSRF(cookies_str)
headers = {
"csrf-token": csrf_token,
"x-li-deco-include-micro-schema": "true",
"x-restli-protocol-version": "2.0.0",
}
response = requests.get(
"https://www.linkedin.com/sales-api/salesApiCredits?q=findCreditGrant&creditGrantType=LSS_INMAIL",
headers=headers,
cookies={"JSESSIONID": csrf_token}, # Assuming this is the only required cookie, otherwise add more as needed
)
data = response.json()
print(data)
What I feel is my current blocker is that this library is authenticating to https://www.linkedin.com/login and actually I wanted it to authenticate to https://www.linkedin.com/sales/login . Any insights on this are welcome. Thank you!
From my experience with linkedin, it same domain - which means it's also same login process If you need any more help, let me know